Helios Engine 0.1.0
A modular ECS based data-oriented C++23 game engine
 
Loading...
Searching...
No Matches
logger.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <helios/core_pch.hpp>
4
5#include <ctti/type_id.hpp>
6
7#include <concepts>
8#include <cstddef>
9#include <cstdint>
10#include <filesystem>
11#include <format>
12#include <memory>
13#include <mutex>
14#include <shared_mutex>
15#include <source_location>
16#include <string>
17#include <string_view>
18#include <type_traits>
19#include <unordered_map>
20#include <utility>
21
22namespace spdlog {
23
24// Forward declaration for spdlog::logger
25class logger;
26
27} // namespace spdlog
28
29namespace helios {
30
31/**
32 * @brief Log severity levels.
33 */
34enum class LogLevel : uint8_t { kTrace = 0, kDebug = 1, kInfo = 2, kWarn = 3, kError = 4, kCritical = 5 };
35
36/**
37 * @brief Configuration for logger behavior and output.
38 */
40 std::filesystem::path log_directory = "logs"; ///< Log output directory path.
41 std::string file_name_pattern =
42 "{name}_{timestamp}.log"; ///< Pattern for log file names (supports format placeholders: {name}, {timestamp}).
43#ifdef HELIOS_ENABLE_STACKTRACE
44 std::string console_pattern = "[%H:%M:%S.%e] [%t] [%^%l%$] %n: %v%*%#"; ///< Console log pattern.
45 std::string file_pattern = "[%Y-%m-%d %H:%M:%S.%e] [%t] [%l] %n: %v%*%#"; ///< File log pattern.
46#else
47 std::string console_pattern = "[%H:%M:%S.%e] [%t] [%^%l%$] %n: %v%*"; ///< Console log pattern.
48 std::string file_pattern = "[%Y-%m-%d %H:%M:%S.%e] [%t] [%l] %n: %v%*"; ///< File log pattern.
49#endif
50
51 size_t max_file_size = 0; ///< Maximum size of a single log file in bytes (0 = no limit).
52 size_t max_files = 0; ///< Maximum number of log files to keep (0 = no limit).
53 LogLevel auto_flush_level = LogLevel::kWarn; ///< Minimum log level to flush automatically.
54
55 bool enable_console = true; ///< Enable console output.
56 bool enable_file = true; ///< Enable file output.
57 bool truncate_files = true; ///< Enable truncation of existing log files.
58 bool async_logging = false; ///< Enable async logging (better performance but may lose last logs on crash).
59
60 LogLevel source_location_level = LogLevel::kError; ///< Minimum level to include source location.
61 LogLevel stack_trace_level = LogLevel::kCritical; ///< Minimum level to include stack trace.
62
63 /**
64 * @brief Creates default configuration.
65 * @return Default LoggerConfig instance
66 */
67 [[nodiscard]] static LoggerConfig Default() noexcept { return {}; }
68
69 /**
70 * @brief Creates configuration for console-only output.
71 * @return LoggerConfig instance for console-only logging
72 */
73 [[nodiscard]] static LoggerConfig ConsoleOnly() noexcept {
74 return LoggerConfig{.enable_console = true, .enable_file = false};
75 }
76
77 /**
78 * @brief Creates configuration for file-only output.
79 * @return LoggerConfig instance for file-only logging
80 */
81 [[nodiscard]] static LoggerConfig FileOnly() noexcept {
82 return LoggerConfig{.enable_console = false, .enable_file = true};
83 }
84
85 /**
86 * @brief Creates configuration optimized for debug builds.
87 * @return LoggerConfig instance for debug logging
88 */
89 [[nodiscard]] static LoggerConfig Debug() noexcept {
90 return LoggerConfig{.enable_console = true, .enable_file = true, .async_logging = false};
91 }
92
93 /**
94 * @brief Creates configuration optimized for release builds.
95 * @return LoggerConfig instance for release logging
96 */
97 [[nodiscard]] static LoggerConfig Release() noexcept {
98 return LoggerConfig{.enable_console = false, .enable_file = true, .async_logging = true};
99 }
100};
101
102/**
103 * @brief Type alias for logger type IDs.
104 * @details Used to uniquely identify logger types at runtime.
105 */
106using LoggerId = size_t;
107
108/**
109 * @brief Trait to identify valid logger types.
110 * @details A valid logger type must be an empty struct or class with a Name() function.
111 *
112 * @example
113 * @code
114 * struct MyLogger {
115 * static constexpr std::string_view Name() noexcept { return "MyLogger"; }
116 * };
117 * static_assert(LoggerTrait<MyLogger>);
118 * @endcode
119 * @tparam T Type to check
120 */
121template <typename T>
122concept LoggerTrait = std::is_empty_v<std::remove_cvref_t<T>> && requires {
123 { T::Name() } -> std::same_as<std::string_view>;
124};
125
126/**
127 * @brief Trait to identify loggers with custom configuration.
128 * @details A logger with config trait must satisfy LoggerTrait and provide:
129 * - `static constexpr LoggerConfig Config() noexcept`
130 *
131 * @example
132 * @code
133 * struct MyLogger {
134 * static constexpr std::string_view Name() noexcept { return "MyLogger"; }
135 * static constexpr LoggerConfig Config() noexcept { return LoggerConfig::Default(); }
136 * };
137 * static_assert(LoggerWithConfigTrait<MyLogger>);
138 * @endcode
139 * @tparam T Type to check
140 */
141template <typename T>
143 { T::Config() } -> std::same_as<LoggerConfig>;
144};
145
146/**
147 * @brief Gets unique type ID for a logger type.
148 * @details Uses CTTI to generate a unique hash for the logger type.
149 * The ID is consistent across compilation units.
150 *
151 * @example
152 * @code
153 * struct MyLogger { static constexpr std::string_view Name() noexcept { return "MyLogger"; } };
154 * constexpr LoggerId id = LoggerIdOf<MyLogger>();
155 * @endcode
156 * @tparam T Logger type
157 * @return Unique type ID for the logger
158 */
159template <LoggerTrait T>
160constexpr LoggerId LoggerIdOf() noexcept {
161 return ctti::type_index_of<T>().hash();
162}
163
164/**
165 * @brief Gets the name of a logger type.
166 * @details Returns the name provided by Name() function.
167 *
168 * @example
169 * @code
170 * struct MyLogger {
171 * static constexpr std::string_view Name() noexcept { return "MyLogger"; }
172 * };
173 * constexpr auto name = LoggerNameOf<MyLogger>(); // "MyLogger"
174 * @endcode
175 * @tparam T Logger type
176 * @return Name of the logger
177 */
178template <LoggerTrait T>
179constexpr std::string_view LoggerNameOf() noexcept {
180 return T::Name();
181}
182
183/**
184 * @brief Gets the configuration for a logger type.
185 * @details Returns the config provided by Config() if available,
186 * otherwise returns the default configuration.
187 *
188 * @example
189 * @code
190 * struct MyLogger {
191 * static constexpr std::string_view Name() noexcept { return "MyLogger"; }
192 * static constexpr LoggerConfig Config() noexcept { return LoggerConfig::ConsoleOnly(); }
193 * };
194 * constexpr auto config = LoggerConfigOf<MyLogger>();
195 * @endcode
196 * @tparam T Logger type
197 * @return Configuration for the logger
198 */
199template <LoggerTrait T>
200inline LoggerConfig LoggerConfigOf() noexcept {
201 if constexpr (LoggerWithConfigTrait<T>) {
202 return T::Config();
203 } else {
204 return LoggerConfig::Default();
205 }
206}
207
208/**
209 * @brief Default logger type.
210 */
212 static constexpr std::string_view Name() noexcept { return "HELIOS"; }
213 static LoggerConfig Config() noexcept {
214#if defined(HELIOS_RELEASE_MODE)
215 return LoggerConfig::Release();
216#else
217 return LoggerConfig::Debug();
218#endif
219 }
220};
221
222/**
223 * @brief Constexpr instance of the default logger for easier user interface.
224 */
225inline constexpr DefaultLogger kDefaultLogger{};
226
227/**
228 * @brief Centralized logging system with configurable output and formatting.
229 * @note Thread-safe.
230 */
231class Logger {
232public:
233 Logger(const Logger&) = delete;
234 Logger(Logger&&) = delete;
235 ~Logger() noexcept = default;
236
237 Logger& operator=(const Logger&) = delete;
238 Logger& operator=(Logger&&) = delete;
239
240 /**
241 * @brief Adds a logger with the specified type and configuration.
242 * @tparam T Logger type
243 * @param logger Logger type instance
244 * @param config Configuration for the logger
245 */
246 template <LoggerTrait T>
247 void AddLogger(T logger, LoggerConfig config = LoggerConfigOf<T>()) noexcept;
248
249 /**
250 * @brief Removes a logger with the given type.
251 * @note Cannot remove the default logger
252 * @tparam T Logger type
253 * @param logger Logger type instance
254 */
255 template <LoggerTrait T>
256 void RemoveLogger(T logger = {}) noexcept;
257
258 /**
259 * @brief Flushes all registered loggers.
260 */
261 void FlushAll() noexcept;
262
263 /**
264 * @brief Flushes a specific logger.
265 * @tparam T Logger type
266 * @param logger Logger type instance
267 */
268 template <LoggerTrait T>
269 void Flush([[maybe_unused]] T logger = {}) noexcept {
270 FlushImpl(LoggerIdOf<T>());
271 }
272
273 /**
274 * @brief Logs a string message with typed logger.
275 * @tparam T Logger type
276 * @param logger Logger type instance
277 * @param level Log severity level
278 * @param loc Source location where the log was triggered
279 * @param message Message to log
280 */
281 template <LoggerTrait T>
282 void LogMessage(T logger, LogLevel level, const std::source_location& loc, std::string_view message) noexcept;
283
284 /**
285 * @brief Logs a formatted message with typed logger.
286 * @tparam T Logger type
287 * @tparam Args Types of the format arguments
288 * @param logger Logger type instance
289 * @param level Log severity level
290 * @param loc Source location where the log was triggered
291 * @param fmt Format string
292 * @param args Arguments for the format string
293 */
294 template <LoggerTrait T, typename... Args>
295 requires(sizeof...(Args) > 0)
296 void LogMessage(T logger, LogLevel level, const std::source_location& loc, std::format_string<Args...> fmt,
297 Args&&... args) noexcept;
298
299 /**
300 * @brief Logs a string message with default logger.
301 * @param level Log severity level
302 * @param loc Source location where the log was triggered
303 * @param message Message to log
304 */
305 void LogMessage(LogLevel level, const std::source_location& loc, std::string_view message) noexcept;
306
307 /**
308 * @brief Logs a formatted message with default logger.
309 * @tparam Args Types of the format arguments
310 * @param level Log severity level
311 * @param loc Source location where the log was triggered
312 * @param fmt Format string
313 * @param args Arguments for the format string
314 */
315 template <typename... Args>
316 requires(sizeof...(Args) > 0)
317 void LogMessage(LogLevel level, const std::source_location& loc, std::format_string<Args...> fmt,
318 Args&&... args) noexcept;
319
320 /**
321 * @brief Logs assertion failure with typed logger.
322 * @tparam T Logger type
323 * @param logger Logger type instance
324 * @param condition The failed condition as a string
325 * @param loc Source location where the assertion failed
326 * @param message Additional message describing the failure
327 */
328 template <LoggerTrait T>
329 void LogAssertionFailure(T logger, std::string_view condition, const std::source_location& loc,
330 std::string_view message) noexcept;
331
332 /**
333 * @brief Logs assertion failure with typed logger (formatted).
334 * @tparam T Logger type
335 * @tparam Args Types of the format arguments
336 * @param logger Logger type instance
337 * @param condition The failed condition as a string
338 * @param loc Source location where the assertion failed
339 * @param fmt Format string for the failure message
340 * @param args Arguments for the format string
341 */
342 template <LoggerTrait T, typename... Args>
343 requires(sizeof...(Args) > 0)
344 void LogAssertionFailure(T logger, std::string_view condition, const std::source_location& loc,
345 std::format_string<Args...> fmt, Args&&... args) noexcept;
346
347 /**
348 * @brief Logs assertion failure with default logger.
349 * @param condition The failed condition as a string
350 * @param loc Source location where the assertion failed
351 * @param message Additional message describing the failure
352 */
353 void LogAssertionFailure(std::string_view condition, const std::source_location& loc,
354 std::string_view message) noexcept;
355
356 /**
357 * @brief Logs assertion failure with default logger (formatted).
358 * @tparam Args Types of the format arguments
359 * @param condition The failed condition as a string
360 * @param loc Source location where the assertion failed
361 * @param fmt Format string for the failure message
362 * @param args Arguments for the format string
363 */
364 template <typename... Args>
365 requires(sizeof...(Args) > 0)
366 void LogAssertionFailure(std::string_view condition, const std::source_location& loc, std::format_string<Args...> fmt,
367 Args&&... args) noexcept;
368
369 /**
370 * @brief Sets the global default configuration for new loggers.
371 * @param config The configuration to use as default
372 */
373 void SetDefaultConfig(const LoggerConfig& config) noexcept { default_config_ = config; }
374
375 /**
376 * @brief Sets the minimum log level for a typed logger.
377 * @tparam T Logger type
378 * @param logger Logger type instance
379 * @param level Minimum log level to set
380 */
381 template <LoggerTrait T>
382 void SetLevel([[maybe_unused]] T logger, LogLevel level) noexcept {
383 SetLevelImpl(LoggerIdOf<T>(), level);
384 }
385
386 /**
387 * @brief Sets the minimum log level for the default logger.
388 * @param level Minimum log level to set
389 */
390 void SetLevel(LogLevel level) noexcept;
391
392 /**
393 * @brief Checks if a logger with the given type exists.
394 * @tparam T Logger type
395 * @param logger Logger type instance
396 * @return True if the logger exists, false otherwise
397 */
398 template <LoggerTrait T>
399 [[nodiscard]] bool HasLogger(T logger = {}) const noexcept;
400
401 /**
402 * @brief Checks if the default logger should log messages at the given level.
403 * @param level The log level to check
404 * @return True if messages at this level should be logged
405 */
406 [[nodiscard]] bool ShouldLog(LogLevel level) const noexcept;
407
408 /**
409 * @brief Checks if a typed logger should log messages at the given level.
410 * @tparam T Logger type
411 * @param logger Logger type instance
412 * @param level The log level to check
413 * @return True if messages at this level should be logged
414 */
415 template <LoggerTrait T>
416 [[nodiscard]] bool ShouldLog([[maybe_unused]] T logger, LogLevel level) const noexcept {
417 return ShouldLogImpl(LoggerIdOf<T>(), level);
418 }
419
420 /**
421 * @brief Gets the current log level for a typed logger.
422 * @tparam T Logger type
423 * @param logger Logger type instance
424 * @return The current log level, or LogLevel::kTrace if logger doesn't exist
425 */
426 template <LoggerTrait T>
427 [[nodiscard]] LogLevel GetLevel([[maybe_unused]] T logger = {}) const noexcept {
428 return GetLevelImpl(LoggerIdOf<T>());
429 }
430
431 /**
432 * @brief Gets the current log level for the default logger.
433 * @return The current log level
434 */
435 [[nodiscard]] LogLevel GetLevel() const noexcept;
436
437 /**
438 * @brief Gets the current default configuration.
439 * @return The default logger configuration
440 */
441 [[nodiscard]] const LoggerConfig& GetDefaultConfig() const noexcept { return default_config_; }
442
443 /**
444 * @brief Gets the singleton instance.
445 * @return Reference to the Logger instance
446 */
447 [[nodiscard]] static Logger& GetInstance() noexcept {
448 static Logger instance;
449 return instance;
450 }
451
452private:
453 Logger() noexcept;
454
455 [[nodiscard]] auto GetLogger(LoggerId logger_id) const noexcept -> std::shared_ptr<spdlog::logger>;
456 [[nodiscard]] auto GetDefaultLogger() const noexcept -> std::shared_ptr<spdlog::logger> {
457 return GetLogger(LoggerIdOf<DefaultLogger>());
458 }
459
460 /**
461 * @brief Flushes a specific logger by ID (internal).
462 * @param logger_id Logger ID
463 */
464 void FlushImpl(LoggerId logger_id) noexcept;
465
466 /**
467 * @brief Sets the minimum log level for a logger by ID (internal).
468 * @param logger_id Logger ID
469 * @param level Minimum log level to set
470 */
471 void SetLevelImpl(LoggerId logger_id, LogLevel level) noexcept;
472
473 /**
474 * @brief Checks if a logger by ID should log messages at the given level (internal).
475 * @param logger_id Logger ID
476 * @param level The log level to check
477 * @return True if messages at this level should be logged
478 */
479 [[nodiscard]] bool ShouldLogImpl(LoggerId logger_id, LogLevel level) const noexcept;
480
481 /**
482 * @brief Gets the current log level for a logger by ID (internal).
483 * @param logger_id Logger ID
484 * @return The current log level, or LogLevel::kTrace if logger doesn't exist
485 */
486 [[nodiscard]] LogLevel GetLevelImpl(LoggerId logger_id) const noexcept;
487
488 static void LogMessageImpl(const std::shared_ptr<spdlog::logger>& logger, LogLevel level,
489 const std::source_location& loc, std::string_view message) noexcept;
490
491 static void LogAssertionFailureImpl(const std::shared_ptr<spdlog::logger>& logger, std::string_view condition,
492 const std::source_location& loc, std::string_view message) noexcept;
493
494 [[nodiscard]] static auto CreateLogger(std::string_view logger_name, const LoggerConfig& config) noexcept
495 -> std::shared_ptr<spdlog::logger>;
496
497 static void DropLoggerFromSpdlog(const std::shared_ptr<spdlog::logger>& logger) noexcept;
498
499 std::unordered_map<LoggerId, std::shared_ptr<spdlog::logger>> loggers_;
500 std::unordered_map<LoggerId, LoggerConfig> logger_configs_;
501 std::unordered_map<LoggerId, LogLevel> logger_levels_;
502 mutable std::shared_mutex loggers_mutex_;
503
504 LoggerConfig default_config_;
505};
506
507inline Logger::Logger() noexcept {
508 default_config_ = LoggerConfigOf<DefaultLogger>();
509
510 constexpr LoggerId default_id = LoggerIdOf<DefaultLogger>();
511 constexpr std::string_view default_name = LoggerNameOf<DefaultLogger>();
512
513 if (auto logger = CreateLogger(default_name, default_config_)) [[likely]] {
514 loggers_.emplace(default_id, std::move(logger));
515 logger_configs_.emplace(default_id, default_config_);
516 logger_levels_.emplace(default_id, LogLevel::kTrace);
517 }
518}
519
520template <LoggerTrait T>
521inline void Logger::AddLogger(T /*logger*/, LoggerConfig config) noexcept {
522 constexpr LoggerId logger_id = LoggerIdOf<T>();
523 constexpr std::string_view logger_name = LoggerNameOf<T>();
524
525 const std::scoped_lock lock(loggers_mutex_);
526 if (loggers_.contains(logger_id)) [[unlikely]] {
527 return;
528 }
529
530 if (auto spdlog_logger = CreateLogger(logger_name, config)) [[likely]] {
531 loggers_.emplace(logger_id, std::move(spdlog_logger));
532 logger_configs_.emplace(logger_id, std::move(config));
533 logger_levels_.emplace(logger_id, LogLevel::kTrace);
534 }
535}
536
537template <LoggerTrait T>
538inline void Logger::RemoveLogger(T /*logger*/) noexcept {
539 constexpr LoggerId logger_id = LoggerIdOf<T>();
540
541 // Cannot remove the default logger
542 if (logger_id == LoggerIdOf<DefaultLogger>()) [[unlikely]] {
543 return;
544 }
545
546 const std::scoped_lock lock(loggers_mutex_);
547 if (const auto it = loggers_.find(logger_id); it != loggers_.end()) {
548 // Unregister from spdlog before erasing
549 DropLoggerFromSpdlog(it->second);
550 loggers_.erase(it);
551 logger_configs_.erase(logger_id);
552 logger_levels_.erase(logger_id);
553 }
554}
555
556template <LoggerTrait T>
557inline void Logger::LogMessage(T /*logger*/, LogLevel level, const std::source_location& loc,
558 std::string_view message) noexcept {
559 if (auto spdlog_logger = GetLogger(LoggerIdOf<T>())) [[likely]] {
560 LogMessageImpl(spdlog_logger, level, loc, message);
561 }
562}
563
564template <LoggerTrait T, typename... Args>
565 requires(sizeof...(Args) > 0)
566inline void Logger::LogMessage(T logger, LogLevel level, const std::source_location& loc,
567 std::format_string<Args...> fmt, Args&&... args) noexcept {
568 try {
569 const std::string message = std::format(fmt, std::forward<Args>(args)...);
570 LogMessage(logger, level, loc, message);
571 } catch (...) {
572 // Silently ignore formatting errors
573 }
574}
575
576inline void Logger::LogMessage(LogLevel level, const std::source_location& loc, std::string_view message) noexcept {
577 if (auto logger = GetDefaultLogger()) [[likely]] {
578 LogMessageImpl(logger, level, loc, message);
579 }
580}
581
582template <typename... Args>
583 requires(sizeof...(Args) > 0)
584inline void Logger::LogMessage(LogLevel level, const std::source_location& loc, std::format_string<Args...> fmt,
585 Args&&... args) noexcept {
586 try {
587 const std::string message = std::format(fmt, std::forward<Args>(args)...);
588 LogMessage(level, loc, message);
589 } catch (...) {
590 // Silently ignore formatting errors
591 }
592}
593
594template <LoggerTrait T>
595inline void Logger::LogAssertionFailure(T /*logger*/, std::string_view condition, const std::source_location& loc,
596 std::string_view message) noexcept {
597 if (auto spdlog_logger = GetLogger(LoggerIdOf<T>())) [[likely]] {
598 LogAssertionFailureImpl(spdlog_logger, condition, loc, message);
599 } else if (auto default_logger = GetDefaultLogger()) [[likely]] {
600 LogAssertionFailureImpl(default_logger, condition, loc, message);
601 }
602}
603
604template <LoggerTrait T, typename... Args>
605 requires(sizeof...(Args) > 0)
606inline void Logger::LogAssertionFailure(T logger, std::string_view condition, const std::source_location& loc,
607 std::format_string<Args...> fmt, Args&&... args) noexcept {
608 try {
609 const std::string message = std::format(fmt, std::forward<Args>(args)...);
610 LogAssertionFailure(logger, condition, loc, message);
611 } catch (...) {
612 LogAssertionFailure(logger, condition, loc, "Formatting error in assertion message");
613 }
614}
615
616inline void Logger::LogAssertionFailure(std::string_view condition, const std::source_location& loc,
617 std::string_view message) noexcept {
618 if (auto logger = GetDefaultLogger()) [[likely]] {
619 LogAssertionFailureImpl(logger, condition, loc, message);
620 }
621}
622
623template <typename... Args>
624 requires(sizeof...(Args) > 0)
625inline void Logger::LogAssertionFailure(std::string_view condition, const std::source_location& loc,
626 std::format_string<Args...> fmt, Args&&... args) noexcept {
627 try {
628 const std::string message = std::format(fmt, std::forward<Args>(args)...);
629 LogAssertionFailure(condition, loc, message);
630 } catch (...) {
631 LogAssertionFailure(condition, loc, "Formatting error in assertion message");
632 }
633}
634
635template <LoggerTrait T>
636inline bool Logger::HasLogger(T /*logger*/) const noexcept {
637 const std::shared_lock lock(loggers_mutex_);
638 return loggers_.contains(LoggerIdOf<T>());
639}
640
641} // namespace helios
642
643// Provide logger integration for assert.hpp
644// On MSVC, we define this in logger.cpp to avoid multiple definition errors
645// On GCC/Clang, the inline definition here takes precedence over the weak symbol in assert.cpp
646namespace helios::details {
647
648#if !defined(_MSC_VER)
649inline void LogAssertionFailureViaLogger(std::string_view condition, const std::source_location& loc,
650 std::string_view message) noexcept {
651 Logger::GetInstance().LogAssertionFailure(condition, loc, message);
652}
653#endif
654
655} // namespace helios::details
656
657// Log level macros
658
659#ifdef HELIOS_DEBUG_MODE
660#define HELIOS_DEBUG(...) \
661 ::helios::Logger::GetInstance().LogMessage(::helios::LogLevel::kDebug, std::source_location::current(), __VA_ARGS__)
662
663#define HELIOS_DEBUG_LOGGER(logger, ...) \
664 ::helios::Logger::GetInstance().LogMessage(logger, ::helios::LogLevel::kDebug, std::source_location::current(), \
665 __VA_ARGS__)
666#else
667#define HELIOS_DEBUG(...) [[maybe_unused]] static constexpr auto HELIOS_ANONYMOUS_VAR(unused_debug) = 0
668#define HELIOS_DEBUG_LOGGER(logger, ...) \
669 [[maybe_unused]] static constexpr auto HELIOS_ANONYMOUS_VAR(unused_debug_logger) = 0
670#endif
671
672#if defined(HELIOS_DEBUG_MODE) || defined(HELIOS_RELEASE_WITH_DEBUG_INFO_MODE)
673#define HELIOS_TRACE(...) \
674 ::helios::Logger::GetInstance().LogMessage(::helios::LogLevel::kTrace, std::source_location::current(), __VA_ARGS__)
675
676#define HELIOS_TRACE_LOGGER(logger, ...) \
677 ::helios::Logger::GetInstance().LogMessage(logger, ::helios::LogLevel::kTrace, std::source_location::current(), \
678 __VA_ARGS__)
679#else
680#define HELIOS_TRACE(...) [[maybe_unused]] static constexpr auto HELIOS_ANONYMOUS_VAR(unused_trace) = 0
681#define HELIOS_TRACE_LOGGER(logger, ...) \
682 [[maybe_unused]] static constexpr auto HELIOS_ANONYMOUS_VAR(unused_trace_logger) = 0
683#endif
684
685#define HELIOS_INFO(...) \
686 ::helios::Logger::GetInstance().LogMessage(::helios::LogLevel::kInfo, std::source_location::current(), __VA_ARGS__)
687#define HELIOS_WARN(...) \
688 ::helios::Logger::GetInstance().LogMessage(::helios::LogLevel::kWarn, std::source_location::current(), __VA_ARGS__)
689#define HELIOS_ERROR(...) \
690 ::helios::Logger::GetInstance().LogMessage(::helios::LogLevel::kError, std::source_location::current(), __VA_ARGS__)
691#define HELIOS_CRITICAL(...) \
692 ::helios::Logger::GetInstance().LogMessage(::helios::LogLevel::kCritical, std::source_location::current(), \
693 __VA_ARGS__)
694
695#define HELIOS_INFO_LOGGER(logger, ...) \
696 ::helios::Logger::GetInstance().LogMessage(logger, ::helios::LogLevel::kInfo, std::source_location::current(), \
697 __VA_ARGS__)
698#define HELIOS_WARN_LOGGER(logger, ...) \
699 ::helios::Logger::GetInstance().LogMessage(logger, ::helios::LogLevel::kWarn, std::source_location::current(), \
700 __VA_ARGS__)
701#define HELIOS_ERROR_LOGGER(logger, ...) \
702 ::helios::Logger::GetInstance().LogMessage(logger, ::helios::LogLevel::kError, std::source_location::current(), \
703 __VA_ARGS__)
704#define HELIOS_CRITICAL_LOGGER(logger, ...) \
705 ::helios::Logger::GetInstance().LogMessage(logger, ::helios::LogLevel::kCritical, std::source_location::current(), \
706 __VA_ARGS__)
Centralized logging system with configurable output and formatting.
Definition logger.hpp:231
void SetLevel(T logger, LogLevel level) noexcept
Sets the minimum log level for a typed logger.
Definition logger.hpp:382
static Logger & GetInstance() noexcept
Gets the singleton instance.
Definition logger.hpp:447
void FlushAll() noexcept
Flushes all registered loggers.
Definition logger.cpp:304
void LogAssertionFailure(T logger, std::string_view condition, const std::source_location &loc, std::string_view message) noexcept
Logs assertion failure with typed logger.
Definition logger.hpp:595
bool HasLogger(T logger={}) const noexcept
Checks if a logger with the given type exists.
Definition logger.hpp:636
bool ShouldLog(LogLevel level) const noexcept
Checks if the default logger should log messages at the given level.
Definition logger.cpp:333
LogLevel GetLevel() const noexcept
Gets the current log level for the default logger.
Definition logger.cpp:340
void AddLogger(T logger, LoggerConfig config=LoggerConfigOf< T >()) noexcept
Adds a logger with the specified type and configuration.
Definition logger.hpp:521
void LogMessage(T logger, LogLevel level, const std::source_location &loc, std::string_view message) noexcept
Logs a string message with typed logger.
Definition logger.hpp:557
Logger(Logger &&)=delete
~Logger() noexcept=default
const LoggerConfig & GetDefaultConfig() const noexcept
Gets the current default configuration.
Definition logger.hpp:441
void SetDefaultConfig(const LoggerConfig &config) noexcept
Sets the global default configuration for new loggers.
Definition logger.hpp:373
void Flush(T logger={}) noexcept
Flushes a specific logger.
Definition logger.hpp:269
Logger(const Logger &)=delete
bool ShouldLog(T logger, LogLevel level) const noexcept
Checks if a typed logger should log messages at the given level.
Definition logger.hpp:416
void RemoveLogger(T logger={}) noexcept
Removes a logger with the given type.
Definition logger.hpp:538
LogLevel GetLevel(T logger={}) const noexcept
Gets the current log level for a typed logger.
Definition logger.hpp:427
void LogAssertionFailureViaLogger(std::string_view condition, const std::source_location &loc, std::string_view message) noexcept
Bridge to logger-provided assertion logging.
Definition logger.hpp:649
LoggerConfig LoggerConfigOf() noexcept
Definition logger.hpp:200
LogLevel
Log severity levels.
Definition logger.hpp:34
constexpr LoggerId LoggerIdOf() noexcept
Definition logger.hpp:160
constexpr std::string_view LoggerNameOf() noexcept
Definition logger.hpp:179
constexpr DefaultLogger kDefaultLogger
Constexpr instance of the default logger for easier user interface.
Definition logger.hpp:225
size_t LoggerId
Type alias for logger type IDs.
Definition logger.hpp:106
STL namespace.
Default logger type.
Definition logger.hpp:211
static LoggerConfig Config() noexcept
Definition logger.hpp:213
static constexpr std::string_view Name() noexcept
Definition logger.hpp:212
Configuration for logger behavior and output.
Definition logger.hpp:39
LogLevel stack_trace_level
Minimum level to include stack trace.
Definition logger.hpp:61
LogLevel source_location_level
Minimum level to include source location.
Definition logger.hpp:60
static LoggerConfig Release() noexcept
Creates configuration optimized for release builds.
Definition logger.hpp:97
bool enable_file
Enable file output.
Definition logger.hpp:56
std::filesystem::path log_directory
Log output directory path.
Definition logger.hpp:40
static LoggerConfig FileOnly() noexcept
Creates configuration for file-only output.
Definition logger.hpp:81
static LoggerConfig Debug() noexcept
Creates configuration optimized for debug builds.
Definition logger.hpp:89
std::string file_name_pattern
Pattern for log file names (supports format placeholders: {name}, {timestamp}).
Definition logger.hpp:41
LogLevel auto_flush_level
Minimum log level to flush automatically.
Definition logger.hpp:53
size_t max_file_size
Maximum size of a single log file in bytes (0 = no limit).
Definition logger.hpp:51
static LoggerConfig ConsoleOnly() noexcept
Creates configuration for console-only output.
Definition logger.hpp:73
bool async_logging
Enable async logging (better performance but may lose last logs on crash).
Definition logger.hpp:58
bool truncate_files
Enable truncation of existing log files.
Definition logger.hpp:57
std::string file_pattern
File log pattern.
Definition logger.hpp:48
std::string console_pattern
Console log pattern.
Definition logger.hpp:47
static LoggerConfig Default() noexcept
Creates default configuration.
Definition logger.hpp:67
bool enable_console
Enable console output.
Definition logger.hpp:55
size_t max_files
Maximum number of log files to keep (0 = no limit).
Definition logger.hpp:52