/** * @file rex/logging/api.h * @brief Logging system function declarations and CVAR declarations * * @copyright Copyright (c) 2026 Tom Clay * All rights reserved. * * @license BSD 3-Clause License * See LICENSE file in the project root for full license text. */ #pragma once #include #include #include #include // Logging CVAR declarations (defined in logging.cpp) REXCVAR_DECLARE(std::string, log_level); REXCVAR_DECLARE(std::string, log_file); REXCVAR_DECLARE(bool, log_verbose); REXCVAR_DECLARE(bool, log_noisy); REXCVAR_DECLARE(int32_t, log_flush_interval); REXCVAR_DECLARE(int32_t, log_max_file_size_mb); REXCVAR_DECLARE(int32_t, log_max_files); namespace rex { /* ========================================================================= Log Level Guidelines ========================================================================= TRACE - Per-instruction, per-iteration detail (massive output) DEBUG - Development info, function entry/exit, intermediate state INFO - Normal operational events, progress updates WARN - Recoverable issues, fallback behaviors, unsupported features ERROR - Serious problems affecting functionality CRITICAL - Fatal errors, memory corruption, unrecoverable state ========================================================================= */ /** * Initialize the logging system with full configuration. * * Creates shared sinks and loggers for all built-in categories. * Safe to call multiple times; subsequent calls update levels only. * * @param config Logging configuration. */ void InitLogging(const LogConfig& config); /** * Initialize logging with simple parameters (convenience overload). * * @param log_file Path to log file, or nullptr for no file logging. * @param level Default log level for all categories. */ void InitLogging(const char* log_file = nullptr, spdlog::level::level_enum level = spdlog::level::info); /** * Early-phase logging initialization (before config is loaded). * Creates a platform debug sink (OutputDebugString on Windows, stdout elsewhere) * so log lines emitted before InitLogging() is called are captured. */ void InitLoggingEarly(); /** * Flush all loggers and shut down the logging system. */ void ShutdownLogging(); /** * Register a new log category at runtime. * * The returned handle can be used with REXLOG_CAT_* macros and all * category-accepting API functions. The category's logger is created * with the current default sinks and any matching entries from the * stored LogConfig::category_levels and LogConfig::category_sinks. * * Thread-safe but intended to be called during startup. * * @param name Human-readable category name (e.g. "app.network"). * @return Handle for the new category. */ LogCategoryId RegisterLogCategory(const char* name); LogCategoryId RegisterLogSubcategory(const char* name, LogCategoryId parent); void SetRootLevel(LogCategoryId root, spdlog::level::level_enum level); /** * Look up a category by name. * * @param name Category name to search for (case-sensitive). * @return Category handle, or std::nullopt if not found. */ std::optional FindCategory(const std::string& name); /** * Get a read-only view of all registered categories. * * @return Span over the registry entries in registration order. */ std::span GetAllCategories(); /** * Get the raw logger pointer for a category (zero overhead). * * This is the fast path used by logging macros. Returns nullptr if * the category is not yet initialized. * * @param category Category handle. * @return Raw pointer to the spdlog logger (not owning). */ spdlog::logger* GetLoggerRaw(LogCategoryId category); /** * Get the shared logger pointer for a category. * * Prefer GetLoggerRaw() in hot paths. This overload is useful when * you need to hold the logger or manipulate its sinks. * * @param category Category handle. * @return Shared pointer to the spdlog logger. */ std::shared_ptr GetLogger(LogCategoryId category); /** * Get the default (Core) logger. * * @return Shared pointer to the Core category logger. */ std::shared_ptr GetLogger(); /** * Set the log level for a specific category at runtime. * * @param category Category handle. * @param level New log level. */ void SetCategoryLevel(LogCategoryId category, spdlog::level::level_enum level); /** * Set the log level for all registered categories. * * @param level New log level. */ void SetAllLevels(spdlog::level::level_enum level); /** * Register a CVAR change callback for the "log_level" CVAR. * Call this after InitLogging() to enable runtime level changes. */ void RegisterLogLevelCallback(); /** * Add a sink to all current and future loggers. * * @param sink Shared pointer to the spdlog sink. */ void AddSink(spdlog::sink_ptr sink); /** * Add a sink to a specific category's logger only. * * @param category Category handle. * @param sink Shared pointer to the spdlog sink. */ void AddSink(LogCategoryId category, spdlog::sink_ptr sink); /** * Remove a sink from all loggers. * * @param sink The sink to remove (matched by pointer identity). */ void RemoveSink(spdlog::sink_ptr sink); /** * Remove a sink from a specific category's logger. * * @param category Category handle. * @param sink The sink to remove (matched by pointer identity). */ void RemoveSink(LogCategoryId category, spdlog::sink_ptr sink); /** * Replace the global console sink on every registered logger with `sink`. * Pass nullptr to remove the console sink without replacement. * * @param sink New console sink, or nullptr to remove. */ void ReplaceConsoleSink(spdlog::sink_ptr sink); /** * Update the format pattern on the stdout console sink. * * @param pattern spdlog pattern string. */ void SetConsolePattern(const std::string& pattern); /** * Update the format pattern on the file sink. * * @param pattern spdlog pattern string. */ void SetFilePattern(const std::string& pattern); /** * Parse a log level string to spdlog level enum. * * Accepts: "trace", "debug", "info", "warn"/"warning", "error"/"err", * "critical", "off". Case-insensitive. * * @param level_str Level name string. * @return Parsed level, or std::nullopt if invalid. */ std::optional ParseLogLevel(const std::string& level_str); /** * Parse log level from string, returning a default on failure. * * @param level_str Level name string. * @param default_level Fallback level if parsing fails. * @return Parsed level or default_level. */ spdlog::level::level_enum ParseLogLevelOr(const std::string& level_str, spdlog::level::level_enum default_level); /** * Build a LogConfig from CLI arguments and environment variables. * * Precedence: CLI args > environment (REX_LOG_LEVEL) > build-type default. * * @param log_file Path to log file, or nullptr. * @param cli_level Global level from CLI (empty string = not set). * @param category_levels Per-category level overrides from CLI. * @return Populated LogConfig. */ LogConfig BuildLogConfig(const char* log_file, const std::string& cli_level, const std::map& category_levels); std::map ParseCategoryLevelsFromConfig( const std::filesystem::path& config_path); } // namespace rex