HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
logger.hpp
1// Copyright Take Vos 2019-2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "counters.hpp"
8#include "time_stamp_count.hpp"
9#include "hires_utc_clock.hpp"
10#include "polymorphic_optional.hpp"
11#include "wfree_fifo.hpp"
12#include "atomic.hpp"
13#include "meta.hpp"
14#include "format.hpp"
15#include "source_location.hpp"
16#include "architecture.hpp"
17#include "delayed_format.hpp"
18#include "fixed_string.hpp"
19#include "subsystem.hpp"
20#include "log_level.hpp"
21#include <chrono>
22#include <format>
23#include <string>
24#include <string_view>
25#include <tuple>
26#include <mutex>
27#include <atomic>
28#include <memory>
29
30namespace tt {
31void trace_record() noexcept;
32}
33
34namespace tt {
35namespace detail {
36
38public:
39 tt_force_inline log_message_base() noexcept = default;
40 virtual ~log_message_base() = default;
41
42 [[nodiscard]] virtual std::string format() const noexcept = 0;
43 [[nodiscard]] virtual std::unique_ptr<log_message_base> make_unique_copy() const noexcept = 0;
44};
45
46template<log_level Level, basic_fixed_string SourceFile, int SourceLine, basic_fixed_string Fmt, typename... Values>
48public:
49 static_assert(std::is_same_v<decltype(SourceFile)::value_type, char>, "SourceFile must be a basic_fixed_string<char>");
50 static_assert(std::is_same_v<decltype(Fmt)::value_type, char>, "Fmt must be a basic_fixed_string<char>");
51
52 log_message(log_message const &) noexcept = default;
53 log_message &operator=(log_message const &) noexcept = default;
54
55 template<typename... Args>
56 tt_force_inline log_message(Args &&...args) noexcept :
57 _time_stamp(time_stamp_count::inplace_with_thread_id{}), _what(std::forward<Args>(args)...)
58 {
59 }
60
61 std::string format() const noexcept override
62 {
63 ttlet time_point = hires_utc_clock::make(_time_stamp);
64 ttlet local_timestring = format_iso8601(time_point);
65 ttlet cpu_id = _time_stamp.cpu_id();
66 ttlet thread_id = _time_stamp.thread_id();
67
68 if constexpr (static_cast<bool>(Level & log_level::statistics)) {
69 return std::format(
70 "{} {:5} {} tid={} cpu={}\n", local_timestring, to_const_string(Level), _what(), thread_id, cpu_id);
71 } else {
72 return std::format(
73 "{} {:5} {} ({}:{}) tid={} cpu={}\n",
74 local_timestring,
75 to_const_string(Level),
76 _what(),
77 SourceFile,
78 SourceLine,
79 thread_id,
80 cpu_id);
81 }
82 }
83
84 [[nodiscard]] std::unique_ptr<log_message_base> make_unique_copy() const noexcept override
85 {
86 return std::make_unique<log_message>(*this);
87 }
88
89private:
90 time_stamp_count _time_stamp;
91 delayed_format<Fmt, Values...> _what;
92};
93
97
100tt_no_inline void logger_deinit() noexcept;
101
107tt_no_inline bool logger_init() noexcept;
108
109inline std::atomic<bool> logger_is_running = false;
110
111} // namespace detail
112
115[[nodiscard]] std::string get_last_error_message() noexcept;
116
121tt_no_inline void logger_flush() noexcept;
122
127inline bool logger_start()
128{
129 return start_subsystem(detail::logger_is_running, false, detail::logger_init, detail::logger_deinit);
130}
131
135inline void logger_stop()
136{
137 return stop_subsystem(detail::logger_deinit);
138}
139
148template<log_level Level, basic_fixed_string SourceFile, int SourceLine, basic_fixed_string Fmt, typename... Args>
149tt_force_inline void log(Args &&...args) noexcept
150{
151 if (!static_cast<bool>(log_level_global.load(std::memory_order::relaxed) & Level)) {
152 return;
153 }
154
155 // Add messages in the queue, block when full.
156 // * This reduces amount of instructions needed to be executed during logging.
157 // * Simplifies logged_fatal_message logic.
158 // * Will make sure everything gets logged.
159 // * Blocking is bad in a real time thread, so maybe count the number of times it is blocked.
160
161 // Emplace a message directly on the queue.
162 detail::log_fifo.emplace<detail::log_message<Level, SourceFile, SourceLine, Fmt, forward_value_t<Args>...>>(
163 std::forward<Args>(args)...);
164
165 if (static_cast<bool>(Level & log_level::fatal) || !detail::logger_is_running.load(std::memory_order::relaxed)) {
166 // If the logger did not start we will log in degraded mode and log from the current thread.
167 // On fatal error we also want to log from the current thread.
168 [[unlikely]] logger_flush();
169 }
170
171 if constexpr (static_cast<bool>(Level & log_level::fatal)) {
173
174 } else if constexpr (static_cast<bool>(Level & log_level::error)) {
175 // Actually logging of tracing will only work when we cleanly unwind the stack and destruct all trace objects.
176 trace_record();
177 }
178}
179
180} // namespace tt
181
182#define tt_log_debug(fmt, ...) ::tt::log<::tt::log_level::debug, __FILE__, __LINE__, fmt>(__VA_ARGS__)
183#define tt_log_info(fmt, ...) ::tt::log<::tt::log_level::info, __FILE__, __LINE__, fmt>(__VA_ARGS__)
184#define tt_log_statistics(fmt, ...) ::tt::log<::tt::log_level::statistics, __FILE__, __LINE__, fmt>(__VA_ARGS__)
185#define tt_log_trace(fmt, ...) ::tt::log<::tt::log_level::trace, __FILE__, __LINE__, fmt>(__VA_ARGS__)
186#define tt_log_audit(fmt, ...) ::tt::log<::tt::log_level::audit, __FILE__, __LINE__, fmt>(__VA_ARGS__)
187#define tt_log_warning(fmt, ...) ::tt::log<::tt::log_level::warning, __FILE__, __LINE__, fmt>(__VA_ARGS__)
188#define tt_log_error(fmt, ...) ::tt::log<::tt::log_level::error, __FILE__, __LINE__, fmt>(__VA_ARGS__)
189#define tt_log_fatal(fmt, ...) \
190 ::tt::log<::tt::log_level::fatal, __FILE__, __LINE__, fmt>(__VA_ARGS__); \
191 tt_unreachable()
STL namespace.
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:30
static time_point make(time_stamp_count const &tsc) noexcept
Make a time point from a time stamp count.
Definition logger.hpp:37
Definition logger.hpp:47
Since Window's 10 QueryPerformanceCounter() counts at only 10MHz which is too low to measure performa...
Definition time_stamp_count.hpp:29
constexpr uint32_t thread_id() const noexcept
Get the thread id.
Definition time_stamp_count.hpp:90
ssize_t cpu_id() const noexcept
Get the logical cpu index.
Definition time_stamp_count.hpp:77
Definition time_stamp_count.hpp:32
A wait-free multiple-producer/single-consumer fifo designed for absolute performance.
Definition wfree_fifo.hpp:23
T terminate(T... args)