7#include "time_stamp_count.hpp"
8#include "time_stamp_utc.hpp"
9#include "wfree_fifo.hpp"
11#include "delayed_format.hpp"
12#include "format_check.hpp"
13#include "utility/module.hpp"
14#include "concurrency/module.hpp"
26namespace hi {
inline namespace v1 {
34 [[nodiscard]]
virtual std::string format()
const noexcept = 0;
38template<
global_state_type Level, fixed_string SourcePath,
int SourceLine, fixed_string Fmt,
typename... Values>
41 static_assert(std::popcount(to_underlying(Level)) == 1);
44 static constexpr char const *log_level_name =
45 Level == global_state_type::log_fatal ?
"fatal" :
46 Level == global_state_type::log_error ?
"error" :
47 Level == global_state_type::log_warning ?
"warning" :
48 Level == global_state_type::log_info ?
"info" :
49 Level == global_state_type::log_debug ?
"debug" :
50 Level == global_state_type::log_trace ?
"trace" :
51 Level == global_state_type::log_audit ?
"audit" :
52 Level == global_state_type::log_statistics ?
"stats" :
53 "<unknown log level>";
59 template<
typename... Args>
60 hi_force_inline
log_message(Args&&...args) noexcept :
61 _time_stamp(time_stamp_count::inplace_with_thread_id{}), _what(std::forward<Args>(args)...)
67 hilet utc_time_point = time_stamp_utc::make(_time_stamp);
68 hilet sys_time_point = std::chrono::clock_cast<std::chrono::system_clock>(utc_time_point);
72 hilet thread_id = _time_stamp.thread_id();
75 if constexpr (to_bool(Level & global_state_type::log_statistics)) {
76 return std::format(
"{} {}({}) {:5} {}\n", local_time_point, thread_name,
cpu_id, log_level_name, _what());
78 auto source_filename = std::filesystem::path{
static_cast<std::string_view
>(SourcePath)}.filename().generic_string();
80 "{} {}({}) {:5} {} ({}:{})\n",
93 return std::make_unique<log_message>(*
this);
97 time_stamp_count _time_stamp;
98 delayed_format<Fmt, Values...> _what;
112 template<
global_state_type Level, fixed_string SourcePath,
int SourceLine, fixed_string Fmt,
typename... Args>
113 hi_force_inline
void add(Args&&...args)
noexcept
115 static_assert(std::popcount(to_underlying(Level)) == 1);
118 if (not to_bool(state & Level)) {
130 std::forward<Args>(args)...);
132 if (to_bool(Level & global_state_type::log_fatal) or not to_bool(state & global_state_type::log_is_running)) {
135 [[unlikely]]
flush();
155 return hi::start_subsystem(global_state_type::log_is_running, log::subsystem_init, log::subsystem_deinit);
169 wfree_fifo<detail::log_message_base, 64> _fifo;
180 static inline std::jthread _log_thread;
184 static void log_thread_main(std::stop_token stop_token)
noexcept;
188 static void subsystem_deinit() noexcept;
195 static
bool subsystem_init() noexcept;
198inline
log log_global;
202#define hi_log(level, fmt, ...) \
203 hi_format_check(fmt __VA_OPT__(, ) __VA_ARGS__); \
204 ::hi::log_global.add<level, __FILE__, __LINE__, fmt>(__VA_ARGS__)
206#define hi_log_debug(fmt, ...) hi_log(::hi::global_state_type::log_debug, fmt __VA_OPT__(, ) __VA_ARGS__)
207#define hi_log_info(fmt, ...) hi_log(::hi::global_state_type::log_info, fmt __VA_OPT__(, ) __VA_ARGS__)
208#define hi_log_statistics(fmt, ...) hi_log(::hi::global_state_type::log_statistics, fmt __VA_OPT__(, ) __VA_ARGS__)
209#define hi_log_trace(fmt, ...) hi_log(::hi::global_state_type::log_trace, fmt __VA_OPT__(, ) __VA_ARGS__)
210#define hi_log_audit(fmt, ...) hi_log(::hi::global_state_type::log_audit, fmt __VA_OPT__(, ) __VA_ARGS__)
211#define hi_log_warning(fmt, ...) hi_log(::hi::global_state_type::log_warning, fmt __VA_OPT__(, ) __VA_ARGS__)
212#define hi_log_error(fmt, ...) hi_log(::hi::global_state_type::log_error, fmt __VA_OPT__(, ) __VA_ARGS__)
213#define hi_log_fatal(fmt, ...) \
214 hi_log(::hi::global_state_type::log_fatal, fmt __VA_OPT__(, ) __VA_ARGS__); \
217#define hi_log_info_once(name, fmt, ...) \
219 if (++global_counter<name> == 1) { \
220 hi_log(::hi::global_state_type::log_info, fmt __VA_OPT__(, ) __VA_ARGS__); \
224#define hi_log_error_once(name, fmt, ...) \
226 if (++global_counter<name> == 1) { \
227 hi_log(::hi::global_state_type::log_error, fmt __VA_OPT__(, ) __VA_ARGS__); \
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
std::string get_thread_name(thread_id id) noexcept
Get the thread name of a thread id.
T::value_type start_subsystem(T &check_variable, typename T::value_type off_value, typename T::value_type(*init_function)(), void(*deinit_function)())
Start a sub-system.
Definition subsystem.hpp:113
std::atomic< global_state_type > global_state
The global state of the hikogui framework.
Definition global_state.hpp:198
global_state_type
The flag-type used for global state.
Definition global_state.hpp:27
void set_log_level(global_state_type log_level) noexcept
Set the logging level.
Definition global_state.hpp:227
void stop_subsystem(void(*deinit_function)())
Stop a sub-system.
Definition subsystem.hpp:199
@ write
Allow write access to a file.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
std::chrono::time_zone const & cached_current_zone() noexcept
Cached current time zone.
Definition time_zone.hpp:36
static bool start_subsystem(global_state_type log_level=global_state_type::log_level_default)
Start the logger system.
Definition log.hpp:152
hi_force_inline void add(Args &&...args) noexcept
Log a message.
Definition log.hpp:113
static void stop_subsystem()
Stop the logger system.
Definition log.hpp:161
hi_no_inline void flush() noexcept
Flush all messages from the log_queue directly from this thread.