GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 83.4% 372 / 0 / 446
Functions: 89.1% 115 / 0 / 129
Branches: 32.5% 100 / 0 / 308

include/DetourModKit/logger.hpp
Line Branch Exec Source
1 #ifndef DETOURMODKIT_LOGGER_HPP
2 #define DETOURMODKIT_LOGGER_HPP
3
4 #include <string>
5 #include <string_view>
6 #include <mutex>
7 #include <memory>
8 #include <chrono>
9 #include <format>
10 #include <atomic>
11
12 #include "DetourModKit/win_file_stream.hpp"
13
14 namespace DetourModKit
15 {
16 /**
17 * @enum LogLevel
18 * @brief Defines the severity levels for log messages.
19 * @note This is an enum class (C++ Core Guidelines Enum.3) to prevent namespace pollution.
20 */
21 enum class LogLevel
22 {
23 Trace = 0,
24 Debug = 1,
25 Info = 2,
26 Warning = 3,
27 Error = 4
28 };
29
30 /**
31 * @brief Converts a LogLevel enum to its string representation.
32 * @param level The LogLevel enum value.
33 * @return std::string_view String representation of the log level.
34 */
35 3360 constexpr std::string_view log_level_to_string(LogLevel level) noexcept
36 {
37
6/6
✓ Branch 2 → 3 taken 24 times.
✓ Branch 2 → 4 taken 21 times.
✓ Branch 2 → 5 taken 3180 times.
✓ Branch 2 → 6 taken 41 times.
✓ Branch 2 → 7 taken 93 times.
✓ Branch 2 → 8 taken 1 time.
3360 switch (level)
38 {
39 24 case LogLevel::Trace:
40 24 return "TRACE";
41 21 case LogLevel::Debug:
42 21 return "DEBUG";
43 3180 case LogLevel::Info:
44 3180 return "INFO";
45 41 case LogLevel::Warning:
46 41 return "WARNING";
47 93 case LogLevel::Error:
48 93 return "ERROR";
49 1 default:
50 1 return "UNKNOWN";
51 }
52 }
53
54 // Logger configuration defaults
55 inline constexpr const char *DEFAULT_LOG_PREFIX = "DetourModKit";
56 inline constexpr const char *DEFAULT_LOG_FILE_NAME = "DetourModKit_Log.txt";
57 inline constexpr const char *DEFAULT_TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S";
58
59 // Forward declarations
60 struct AsyncLoggerConfig;
61 class AsyncLogger;
62
63 /**
64 * @class Logger
65 * @brief A singleton class for logging messages to a file.
66 * @details Provides thread-safe logging with configurable levels, timestamps,
67 * and log file location. Uses atomic LogLevel for thread-safe level changes.
68 */
69 class Logger
70 {
71 public:
72 /**
73 * @brief Retrieves the singleton instance of the Logger.
74 * @return Logger& Reference to the single Logger instance.
75 */
76 1230 static Logger &get_instance()
77 {
78
4/8
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 8 taken 1229 times.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 10 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
1230 static Logger instance;
79 1230 return instance;
80 }
81
82 /**
83 * @brief Configures global static settings for the logger before first instantiation.
84 * @details If the logger instance already exists, this will also reconfigure the instance
85 * by reopening the log file with the new settings.
86 * @param prefix Default log prefix string.
87 * @param file_name Default log file name.
88 * @param timestamp_fmt Default timestamp format string (strftime compatible).
89 */
90 static void configure(std::string_view prefix, std::string_view file_name, std::string_view timestamp_fmt);
91
92 /**
93 * @brief Reconfigures an existing logger instance with new settings.
94 * @details Closes the current log file (if open) and reopens it with the new settings.
95 * Thread-safe. Logs a message about the reconfiguration.
96 * @param prefix New log prefix string.
97 * @param file_name New log file name.
98 * @param timestamp_fmt New timestamp format string (strftime compatible).
99 */
100 void reconfigure(std::string_view prefix, std::string_view file_name, std::string_view timestamp_fmt);
101
102 /**
103 * @brief Enables asynchronous logging mode.
104 * @details When enabled, log messages are queued and written by a dedicated
105 * writer thread, reducing latency on the calling thread.
106 * @param config Optional async logger configuration. Uses defaults if not provided.
107 */
108 void enable_async_mode(const AsyncLoggerConfig &config);
109 void enable_async_mode();
110
111 /**
112 * @brief Disables asynchronous logging mode and returns to synchronous mode.
113 * @details Flushes all pending async messages before switching.
114 */
115 void disable_async_mode();
116
117 /**
118 * @brief Checks if async logging mode is enabled.
119 * @return true if async mode is enabled, false otherwise.
120 */
121 bool is_async_mode_enabled() const;
122
123 /**
124 * @brief Flushes all pending log messages.
125 * @details In async mode, waits for all queued messages to be written.
126 * In sync mode, flushes the file stream.
127 */
128 void flush();
129
130 /**
131 * @brief Explicitly shuts down the Logger, closing files without logging.
132 * @details This method is safe to call during shutdown. It closes the log file
133 * and shuts down async logger without attempting to log, preventing
134 * use-after-free if called after other singletons are destroyed.
135 * After calling shutdown(), the destructor becomes a no-op.
136 */
137 void shutdown();
138
139 /**
140 * @brief Gets the current log level.
141 * @return LogLevel The current minimum log level.
142 */
143 13 LogLevel get_log_level() const
144 {
145 13 return current_log_level_.load(std::memory_order_acquire);
146 }
147
148 /**
149 * @brief Checks whether messages at the given level would be logged.
150 * @details Useful for gating expensive trace-only work (e.g. iterating
151 * a data structure solely to build a log message).
152 * @param level The LogLevel to test.
153 * @return true if a message at this level would pass the current filter.
154 */
155 40 bool is_enabled(LogLevel level) const noexcept
156 {
157 40 return level >= current_log_level_.load(std::memory_order_acquire);
158 }
159
160 /**
161 * @brief Sets the minimum log level for messages to be recorded.
162 * @param level The minimum LogLevel to record.
163 */
164 void set_log_level(LogLevel level);
165
166 /**
167 * @brief Logs a message if its level is at or above the current log level.
168 * @param level The LogLevel of the message.
169 * @param message The message string to log.
170 */
171 void log(LogLevel level, std::string_view message);
172
173 /**
174 * @brief Logs a formatted message with the specified log level.
175 * @details Uses std::format-style placeholders. Arguments are only formatted
176 * if the log level is enabled (lazy evaluation).
177 * @tparam Args Types of the format arguments.
178 * @param level The LogLevel of the message.
179 * @param fmt The format string with {} placeholders.
180 * @param args The arguments to substitute into the format string.
181 */
182 template <typename... Args>
183 2557 void log(LogLevel level, std::format_string<Args...> fmt, Args &&...args)
184 {
185
56/98
void DetourModKit::Logger::log<>(DetourModKit::LogLevel, std::basic_format_string<char>):
✓ Branch 3 → 4 taken 60 times.
✓ Branch 3 → 9 taken 458 times.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 2 times.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<unsigned long>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, unsigned long&&):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 15 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<unsigned long>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, unsigned long&&):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 13 not taken.
void DetourModKit::Logger::log<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<char const*>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type>, char const*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 13 not taken.
void DetourModKit::Logger::log<void*>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<void*>::type>, void*&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 1 time.
void DetourModKit::Logger::log<char const (&) [6]>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<char const (&) [6]>::type>, char const (&) [6]):
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 11 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 1 time.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<char const*>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 1 time.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, float const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<float const&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, float const&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 1 time.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<int const&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int const&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 4 times.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 4 times.
void DetourModKit::Logger::log<int const&, int&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int const&>::type, std::type_identity<int&>::type>, int const&, int&):
✓ Branch 3 → 4 taken 796 times.
✓ Branch 3 → 13 taken 3 times.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&):
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 11 taken 117 times.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char const*>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type, std::type_identity<char const*>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char const*&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 14 times.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type, std::type_identity<int&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int&):
✓ Branch 3 → 4 taken 26 times.
✗ Branch 3 → 13 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned long long&, char const*>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type, std::type_identity<unsigned long long&>::type, std::type_identity<char const*>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned long long&, char const*&&):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 15 not taken.
void DetourModKit::Logger::log<void*&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<void*&>::type>, void*&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 1 time.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type>, std::basic_string_view<char, std::char_traits<char> >&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 113 times.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type>, std::basic_string_view<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 17 taken 3 times.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::basic_string_view<char, std::char_traits<char> > >::type>, std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 185 times.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type>, std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&):
✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 13 not taken.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type>, std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 15 taken 10 times.
void DetourModKit::Logger::log<int&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int&>::type>, int&):
✓ Branch 3 → 4 taken 182 times.
✓ Branch 3 → 11 taken 3 times.
void DetourModKit::Logger::log<int&, int&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int&>::type, std::type_identity<int&>::type>, int&, int&):
✓ Branch 3 → 4 taken 25 times.
✗ Branch 3 → 13 not taken.
void DetourModKit::Logger::log<unsigned long long&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long&>::type>, unsigned long long&):
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 11 taken 130 times.
void DetourModKit::Logger::log<unsigned long long&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long&>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type>, unsigned long long&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 6 times.
void DetourModKit::Logger::log<unsigned long long&, unsigned long long const&, unsigned int&, unsigned long long const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long&>::type, std::type_identity<unsigned long long const&>::type, std::type_identity<unsigned int&>::type, std::type_identity<unsigned long long const&>::type>, unsigned long long&, unsigned long long const&, unsigned int&, unsigned long long const&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 17 taken 167 times.
void DetourModKit::Logger::log<unsigned long long&, unsigned long long&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long&>::type, std::type_identity<unsigned long long&>::type>, unsigned long long&, unsigned long long&):
✓ Branch 3 → 4 taken 16 times.
✓ Branch 3 → 13 taken 3 times.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> > >::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<unsigned long long>::type>, std::basic_string_view<char, std::char_traits<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long long&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 15 taken 26 times.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >, std::basic_string_view<char, std::char_traits<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> > >::type, std::type_identity<std::basic_string_view<char, std::char_traits<char> > >::type>, std::basic_string_view<char, std::char_traits<char> >&&, std::basic_string_view<char, std::char_traits<char> >&&):
✓ Branch 3 → 4 taken 20 times.
✓ Branch 3 → 13 taken 12 times.
void DetourModKit::Logger::log<bool>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<bool>::type>, bool&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 3 times.
void DetourModKit::Logger::log<char>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<char>::type>, char&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 1 time.
void DetourModKit::Logger::log<double>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<double>::type>, double&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 3 times.
void DetourModKit::Logger::log<float>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<float>::type>, float&&):
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 11 taken 2 times.
void DetourModKit::Logger::log<int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type>, int&&):
✓ Branch 3 → 4 taken 18 times.
✓ Branch 3 → 11 taken 17 times.
void DetourModKit::Logger::log<int, char const (&) [4], float>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<char const (&) [4]>::type, std::type_identity<float>::type>, int&&, char const (&) [4], float&&):
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 15 not taken.
void DetourModKit::Logger::log<int, char const (&) [4], float, bool, char>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<char const (&) [4]>::type, std::type_identity<float>::type, std::type_identity<bool>::type, std::type_identity<char>::type>, int&&, char const (&) [4], float&&, bool&&, char&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 19 taken 1 time.
void DetourModKit::Logger::log<int, double>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<double>::type>, int&&, double&&):
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 13 not taken.
void DetourModKit::Logger::log<int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&):
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 13 taken 1 time.
void DetourModKit::Logger::log<int, int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&, int&&):
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 15 taken 1 time.
void DetourModKit::Logger::log<int, int, int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&, int&&, int&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 17 taken 1 time.
void DetourModKit::Logger::log<int, int, int, int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&, int&&, int&&, int&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 19 taken 1 time.
void DetourModKit::Logger::log<int, int, int, int, int, int, int, int, int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&, int&&, int&&, int&&, int&&, int&&, int&&, int&&, int&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 29 taken 1 time.
void DetourModKit::Logger::log<long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<long>::type>, long&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 1 time.
void DetourModKit::Logger::log<unsigned long long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long>::type>, unsigned long long&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 11 taken 3 times.
void DetourModKit::Logger::log<unsigned long long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type>, unsigned long long&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 68 times.
void DetourModKit::Logger::log<unsigned long long, long long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long>::type, std::type_identity<long long>::type>, unsigned long long&&, long long&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 20 times.
void DetourModKit::Logger::log<unsigned long long, unsigned long long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long>::type, std::type_identity<unsigned long long>::type>, unsigned long long&&, unsigned long long&&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 6 times.
2557 if (level >= current_log_level_.load(std::memory_order_acquire))
186 {
187
34/196
void DetourModKit::Logger::log<>(DetourModKit::LogLevel, std::basic_format_string<char>):
✓ Branch 4 → 5 taken 60 times.
✗ Branch 4 → 12 not taken.
✓ Branch 6 → 7 taken 60 times.
✗ Branch 6 → 10 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<unsigned long>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, unsigned long&&):
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 18 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 16 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<unsigned long>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, unsigned long&&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<char const*>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type>, char const*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<void*>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<void*>::type>, void*&&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<char const (&) [6]>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<char const (&) [6]>::type>, char const (&) [6]):
✓ Branch 6 → 7 taken 5 times.
✗ Branch 6 → 14 not taken.
✓ Branch 8 → 9 taken 5 times.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<char const*>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*&&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, float const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<float const&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, float const&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<int const&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int const&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<int const&, int&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int const&>::type, std::type_identity<int&>::type>, int const&, int&):
✓ Branch 8 → 9 taken 775 times.
✗ Branch 8 → 16 not taken.
✓ Branch 10 → 11 taken 798 times.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&):
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 14 not taken.
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char const*>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type, std::type_identity<char const*>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char const*&&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type, std::type_identity<int&>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int&):
✓ Branch 8 → 9 taken 26 times.
✗ Branch 8 → 16 not taken.
✓ Branch 10 → 11 taken 26 times.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned long long&, char const*>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type, std::type_identity<unsigned long long&>::type, std::type_identity<char const*>::type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned long long&, char const*&&):
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 18 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 16 not taken.
void DetourModKit::Logger::log<void*&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<void*&>::type>, void*&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type>, std::basic_string_view<char, std::char_traits<char> >&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type>, std::basic_string_view<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 20 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 18 not taken.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::basic_string_view<char, std::char_traits<char> > >::type>, std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type>, std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&):
✓ Branch 8 → 9 taken 7 times.
✗ Branch 8 → 16 not taken.
✓ Branch 10 → 11 taken 7 times.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::basic_string_view<char, std::char_traits<char> >&>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type>, std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 18 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 16 not taken.
void DetourModKit::Logger::log<int&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int&>::type>, int&):
✓ Branch 6 → 7 taken 182 times.
✗ Branch 6 → 14 not taken.
✓ Branch 8 → 9 taken 182 times.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<int&, int&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int&>::type, std::type_identity<int&>::type>, int&, int&):
✓ Branch 8 → 9 taken 25 times.
✗ Branch 8 → 16 not taken.
✓ Branch 10 → 11 taken 25 times.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<unsigned long long&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long&>::type>, unsigned long long&):
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 14 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<unsigned long long&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long&>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type>, unsigned long long&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<unsigned long long&, unsigned long long const&, unsigned int&, unsigned long long const&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long&>::type, std::type_identity<unsigned long long const&>::type, std::type_identity<unsigned int&>::type, std::type_identity<unsigned long long const&>::type>, unsigned long long&, unsigned long long const&, unsigned int&, unsigned long long const&):
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 20 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 18 not taken.
void DetourModKit::Logger::log<unsigned long long&, unsigned long long&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long&>::type, std::type_identity<unsigned long long&>::type>, unsigned long long&, unsigned long long&):
✓ Branch 8 → 9 taken 16 times.
✗ Branch 8 → 16 not taken.
✓ Branch 10 → 11 taken 16 times.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> > >::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type, std::type_identity<unsigned long long>::type>, std::basic_string_view<char, std::char_traits<char> >&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long long&&):
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 18 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 16 not taken.
void DetourModKit::Logger::log<std::basic_string_view<char, std::char_traits<char> >, std::basic_string_view<char, std::char_traits<char> > >(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<std::basic_string_view<char, std::char_traits<char> > >::type, std::type_identity<std::basic_string_view<char, std::char_traits<char> > >::type>, std::basic_string_view<char, std::char_traits<char> >&&, std::basic_string_view<char, std::char_traits<char> >&&):
✓ Branch 8 → 9 taken 20 times.
✗ Branch 8 → 16 not taken.
✓ Branch 10 → 11 taken 20 times.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<bool>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<bool>::type>, bool&&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<char>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<char>::type>, char&&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<double>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<double>::type>, double&&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<float>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<float>::type>, float&&):
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 14 not taken.
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type>, int&&):
✓ Branch 6 → 7 taken 18 times.
✗ Branch 6 → 14 not taken.
✓ Branch 8 → 9 taken 18 times.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<int, char const (&) [4], float>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<char const (&) [4]>::type, std::type_identity<float>::type>, int&&, char const (&) [4], float&&):
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 16 not taken.
void DetourModKit::Logger::log<int, char const (&) [4], float, bool, char>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<char const (&) [4]>::type, std::type_identity<float>::type, std::type_identity<bool>::type, std::type_identity<char>::type>, int&&, char const (&) [4], float&&, bool&&, char&&):
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 22 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 20 not taken.
void DetourModKit::Logger::log<int, double>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<double>::type>, int&&, double&&):
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 16 not taken.
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&):
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 16 not taken.
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<int, int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&, int&&):
✓ Branch 10 → 11 taken 5 times.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 5 times.
✗ Branch 12 → 16 not taken.
void DetourModKit::Logger::log<int, int, int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&, int&&, int&&):
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 20 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 18 not taken.
void DetourModKit::Logger::log<int, int, int, int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&, int&&, int&&, int&&):
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 22 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 20 not taken.
void DetourModKit::Logger::log<int, int, int, int, int, int, int, int, int, int>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type, std::type_identity<int>::type>, int&&, int&&, int&&, int&&, int&&, int&&, int&&, int&&, int&&, int&&):
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 32 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 30 not taken.
void DetourModKit::Logger::log<long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<long>::type>, long&&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<unsigned long long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long>::type>, unsigned long long&&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 14 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
void DetourModKit::Logger::log<unsigned long long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long>::type, std::type_identity<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type>, unsigned long long&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<unsigned long long, long long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long>::type, std::type_identity<long long>::type>, unsigned long long&&, long long&&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
void DetourModKit::Logger::log<unsigned long long, unsigned long long>(DetourModKit::LogLevel, std::basic_format_string<char, std::type_identity<unsigned long long>::type, std::type_identity<unsigned long long>::type>, unsigned long long&&, unsigned long long&&):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
2076 log(level, std::format(fmt, std::forward<Args>(args)...));
188 }
189 2564 }
190
191 /// @name Convenience log methods
192 /// Shorthand for `log(LogLevel::X, fmt, args...)`. See log() for parameter docs.
193 /// @{
194 template <typename... Args>
195 16 void trace(std::format_string<Args...> fmt, Args &&...args)
196 {
197 19 log(LogLevel::Trace, fmt, std::forward<Args>(args)...);
198 16 }
199
200 template <typename... Args>
201 850 void debug(std::format_string<Args...> fmt, Args &&...args)
202 {
203 1442 log(LogLevel::Debug, fmt, std::forward<Args>(args)...);
204 850 }
205
206 template <typename... Args>
207 1278 void info(std::format_string<Args...> fmt, Args &&...args)
208 {
209 2236 log(LogLevel::Info, fmt, std::forward<Args>(args)...);
210 1281 }
211
212 template <typename... Args>
213 299 void warning(std::format_string<Args...> fmt, Args &&...args)
214 {
215 486 log(LogLevel::Warning, fmt, std::forward<Args>(args)...);
216 303 }
217
218 template <typename... Args>
219 56 void error(std::format_string<Args...> fmt, Args &&...args)
220 {
221 91 log(LogLevel::Error, fmt, std::forward<Args>(args)...);
222 56 }
223 /// @}
224
225 /**
226 * @brief Converts a log level string to the LogLevel enum.
227 * @param level_str The string to convert (case-insensitive).
228 * @return The corresponding LogLevel enum. Defaults to LogLevel::Info if unrecognized.
229 */
230 static LogLevel string_to_log_level(std::string_view level_str);
231
232 /**
233 * @struct StaticConfig
234 * @brief Immutable configuration snapshot for thread-safe static configuration.
235 * @details Stored behind an atomic shared_ptr so readers never need a mutex.
236 */
237 struct StaticConfig
238 {
239 std::string log_prefix;
240 std::string log_file_name;
241 std::string timestamp_format;
242
243 198 StaticConfig(std::string prefix, std::string file, std::string ts_fmt)
244 396 : log_prefix(std::move(prefix)),
245 396 log_file_name(std::move(file)),
246 396 timestamp_format(std::move(ts_fmt)) {}
247 };
248
249 private:
250 Logger();
251 ~Logger() noexcept;
252
253 Logger(const Logger &) = delete;
254 Logger &operator=(const Logger &) = delete;
255 Logger(Logger &&) = delete;
256 Logger &operator=(Logger &&) = delete;
257
258 /**
259 * @brief Shared shutdown logic used by both ~Logger() and shutdown().
260 */
261 void shutdown_internal();
262
263 /**
264 * @brief Generates the current timestamp formatted according to timestamp_format_.
265 * @return std::string The formatted timestamp string.
266 */
267 std::string get_timestamp() const;
268
269 /**
270 * @brief Determines the full path for the log file.
271 * @return std::string The absolute path to the log file.
272 */
273 std::string generate_log_file_path() const;
274
275 static std::shared_ptr<const StaticConfig> get_static_config();
276 static void set_static_config(std::shared_ptr<const StaticConfig> config);
277
278 // Lock ordering (must be acquired in this order to prevent deadlock):
279 // 1. async_mutex_ — async logger lifecycle
280 // 2. *log_mutex_ptr_ — file stream I/O
281
282 std::string log_prefix_;
283 std::string log_file_name_;
284 std::string timestamp_format_;
285
286 std::shared_ptr<WinFileStream> log_file_stream_ptr_;
287 std::shared_ptr<std::mutex> log_mutex_ptr_;
288 std::atomic<LogLevel> current_log_level_{LogLevel::Info};
289 std::atomic<bool> shutdown_called_{false};
290
291 // Async logging support (forward declared).
292 // async_logger_ is atomic for lock-free reads on the log() hot path.
293 // async_mutex_ serializes lifecycle operations (enable/disable/shutdown).
294 std::atomic<std::shared_ptr<AsyncLogger>> async_logger_{};
295 std::atomic<bool> async_mode_enabled_{false};
296 std::mutex async_mutex_;
297 };
298 } // namespace DetourModKit
299
300 #endif // DETOURMODKIT_LOGGER_HPP
301