LCOV - code coverage report
Current view: top level - wirestead/diagnostics - logger.hpp (source / functions) Coverage Total Hit
Test: Wirestead Coverage Report Lines: 100.0 % 11 11
Test Date: 2026-08-30 10:35:09 Functions: 100.0 % 3 3
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * Copyright 2025 Jinwoo Sung
       3                 :             :  *
       4                 :             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :             :  * you may not use this file except in compliance with the License.
       6                 :             :  * You may obtain a copy of the License at
       7                 :             :  *
       8                 :             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :             :  *
      10                 :             :  * Unless required by applicable law or agreed to in writing, software
      11                 :             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :             :  * See the License for the specific language governing permissions and
      14                 :             :  * limitations under the License.
      15                 :             :  */
      16                 :             : 
      17                 :             : #pragma once
      18                 :             : 
      19                 :             : #include <atomic>
      20                 :             : #include <chrono>
      21                 :             : #include <functional>
      22                 :             : #include <memory>
      23                 :             : #include <source_location>
      24                 :             : #include <string>
      25                 :             : #include <string_view>
      26                 :             : #include <vector>
      27                 :             : 
      28                 :             : #include "wirestead/base/visibility.hpp"
      29                 :             : 
      30                 :             : #ifdef DEBUG
      31                 :             : #undef DEBUG
      32                 :             : #endif
      33                 :             : #ifdef INFO
      34                 :             : #undef INFO
      35                 :             : #endif
      36                 :             : #ifdef WARNING
      37                 :             : #undef WARNING
      38                 :             : #endif
      39                 :             : #ifdef ERROR
      40                 :             : #undef ERROR
      41                 :             : #endif
      42                 :             : #ifdef CRITICAL
      43                 :             : #undef CRITICAL
      44                 :             : #endif
      45                 :             : #ifdef CALLBACK
      46                 :             : #undef CALLBACK
      47                 :             : #endif
      48                 :             : 
      49                 :             : namespace wirestead {
      50                 :             : namespace diagnostics {
      51                 :             : 
      52                 :             : /**
      53                 :             :  * @brief Log severity levels
      54                 :             :  */
      55                 :             : enum class LogLevel { DEBUG = 0, INFO = 1, WARNING = 2, ERROR = 3, CRITICAL = 4 };
      56                 :             : 
      57                 :             : /**
      58                 :             :  * @brief Log output destinations
      59                 :             :  */
      60                 :             : enum class LogOutput { CONSOLE = 0x01, FILE = 0x02, CALLBACK = 0x04 };
      61                 :             : 
      62                 :             : /**
      63                 :             :  * @brief Log rotation configuration
      64                 :             :  */
      65                 :             : struct LogRotationConfig {
      66                 :             :   size_t max_file_size_bytes = 10 * 1024 * 1024;    // 10MB default
      67                 :             :   size_t max_files = 10;                            // Keep 10 files max
      68                 :             :   bool enable_compression = false;                  // Reserved for future use
      69                 :             :   std::string file_pattern = "{name}.{index}.log";  // Reserved for future use
      70                 :             : 
      71                 :        1239 :   LogRotationConfig() = default;
      72                 :             : 
      73                 :             :   LogRotationConfig(size_t max_size, size_t max_count) : max_file_size_bytes(max_size), max_files(max_count) {}
      74                 :             : };
      75                 :             : 
      76                 :             : /**
      77                 :             :  * @brief Async logging configuration
      78                 :             :  */
      79                 :             : struct AsyncLogConfig {
      80                 :             :   size_t max_queue_size = 10000;                     // Maximum queue size
      81                 :             :   size_t batch_size = 100;                           // Reserved; spdlog manages batching internally
      82                 :         350 :   std::chrono::milliseconds flush_interval{100};     // Flush interval
      83                 :         350 :   std::chrono::milliseconds shutdown_timeout{5000};  // Shutdown timeout
      84                 :             :   bool enable_backpressure = true;                   // Enable backpressure handling (maps to spdlog block policy)
      85                 :             :   bool enable_batch_processing = true;               // Reserved; spdlog manages batching internally
      86                 :             : 
      87                 :         350 :   AsyncLogConfig() = default;
      88                 :             : 
      89                 :             :   AsyncLogConfig(size_t max_q, size_t batch, std::chrono::milliseconds interval)
      90                 :             :       : max_queue_size(max_q), batch_size(batch), flush_interval(interval) {}
      91                 :             : };
      92                 :             : 
      93                 :             : /**
      94                 :             :  * @brief Centralized logging system with async support
      95                 :             :  *
      96                 :             :  * Provides thread-safe, configurable logging with multiple output destinations,
      97                 :             :  * async processing, batch operations, and performance optimizations for production use.
      98                 :             :  */
      99                 :             : class WIRESTEAD_API Logger {
     100                 :             :  public:
     101                 :             :   using LogCallback = std::function<void(LogLevel level, const std::string& formatted_message)>;
     102                 :             : 
     103                 :             :   /**
     104                 :             :    * @brief Get singleton instance
     105                 :             :    */
     106                 :             :   static Logger& instance();
     107                 :             :   [[deprecated("Use Logger::instance() instead")]]
     108                 :             :   static Logger& default_logger();
     109                 :             : 
     110                 :             :   Logger();
     111                 :             :   ~Logger();
     112                 :             : 
     113                 :             :   // Move semantics
     114                 :             :   Logger(Logger&&) noexcept;
     115                 :             :   Logger& operator=(Logger&&) noexcept;
     116                 :             : 
     117                 :             :   // Non-copyable
     118                 :             :   Logger(const Logger&) = delete;
     119                 :             :   Logger& operator=(const Logger&) = delete;
     120                 :             : 
     121                 :             :   /**
     122                 :             :    * @brief Set minimum log level
     123                 :             :    * @param level Messages below this level will be ignored
     124                 :             :    */
     125                 :             :   void set_level(LogLevel level);
     126                 :             : 
     127                 :             :   /**
     128                 :             :    * @brief Get current log level
     129                 :             :    */
     130                 :             :   LogLevel level() const;
     131                 :             : 
     132                 :             :   /**
     133                 :             :    * @brief Check whether a message at the given level would be logged.
     134                 :             :    */
     135                 :             :   bool should_log(LogLevel level) const;
     136                 :             : 
     137                 :             :   /**
     138                 :             :    * @brief Enable/disable console output
     139                 :             :    * @param enable True to enable console output
     140                 :             :    */
     141                 :             :   void set_console_output(bool enable);
     142                 :             : 
     143                 :             :   /**
     144                 :             :    * @brief Set file output
     145                 :             :    * @param filename Log file path (empty string to disable file output)
     146                 :             :    */
     147                 :             :   void set_file_output(const std::string& filename);
     148                 :             : 
     149                 :             :   /**
     150                 :             :    * @brief Set file output and report whether it succeeded.
     151                 :             :    * @param filename Log file path (empty string to disable file output)
     152                 :             :    * @return True when the requested output state was applied
     153                 :             :    */
     154                 :             :   bool try_set_file_output(const std::string& filename);
     155                 :             : 
     156                 :             :   /**
     157                 :             :    * @brief Set file output with rotation
     158                 :             :    * @param filename Log file path
     159                 :             :    * @param config Rotation configuration
     160                 :             :    */
     161                 :             :   void set_file_output_with_rotation(const std::string& filename,
     162                 :             :                                      const LogRotationConfig& config = LogRotationConfig{});
     163                 :             : 
     164                 :             :   /**
     165                 :             :    * @brief Set file output with rotation and report whether it succeeded.
     166                 :             :    * @param filename Log file path
     167                 :             :    * @param config Rotation configuration
     168                 :             :    * @return True when the requested output state was applied
     169                 :             :    */
     170                 :             :   bool try_set_file_output_with_rotation(const std::string& filename,
     171                 :             :                                          const LogRotationConfig& config = LogRotationConfig{});
     172                 :             : 
     173                 :             :   /**
     174                 :             :    * @brief Enable/disable async logging
     175                 :             :    * @param enable True to enable async logging
     176                 :             :    * @param config Async logging configuration
     177                 :             :    */
     178                 :             :   void set_async_logging(bool enable, const AsyncLogConfig& config = AsyncLogConfig{});
     179                 :             : 
     180                 :             :   /**
     181                 :             :    * @brief Check if async logging is enabled
     182                 :             :    */
     183                 :             :   bool async_logging_enabled() const;
     184                 :             : 
     185                 :             :   /**
     186                 :             :    * @brief Re-apply supported logger settings from environment variables.
     187                 :             :    *
     188                 :             :    * Currently supports WIRESTEAD_LOG_LEVEL values DEBUG, INFO, WARNING, ERROR, CRITICAL, and OFF.
     189                 :             :    */
     190                 :             :   void reload_from_environment();
     191                 :             : 
     192                 :             :   /**
     193                 :             :    * @brief Set log callback
     194                 :             :    * @param callback Function to call for each log message
     195                 :             :    */
     196                 :             :   void set_callback(LogCallback callback);
     197                 :             : 
     198                 :             :   /**
     199                 :             :    * @brief Set output destinations
     200                 :             :    * @param outputs Bitwise OR of LogOutput flags
     201                 :             :    */
     202                 :             :   void set_outputs(int outputs);
     203                 :             : 
     204                 :             :   /**
     205                 :             :    * @brief Enable/disable logging
     206                 :             :    * @param enabled True to enable logging
     207                 :             :    */
     208                 :             :   void set_enabled(bool enabled);
     209                 :             : 
     210                 :             :   /**
     211                 :             :    * @brief Check if logging is enabled
     212                 :             :    */
     213                 :             :   bool enabled() const;
     214                 :             : 
     215                 :             :   /**
     216                 :             :    * @brief Return true when at least one output destination is active.
     217                 :             :    */
     218                 :             :   bool has_outputs() const;
     219                 :             : 
     220                 :             :   /**
     221                 :             :    * @brief Last logger configuration error, empty when the last operation succeeded.
     222                 :             :    */
     223                 :             :   std::string last_error() const;
     224                 :             : 
     225                 :             :   /**
     226                 :             :    * @brief Set log format
     227                 :             :    * @param format Format string with placeholders: {timestamp}, {level}, {component}, {operation}, {source}, {file},
     228                 :             :    * {line}, {function}, {message}
     229                 :             :    */
     230                 :             :   void set_format(const std::string& format);
     231                 :             : 
     232                 :             :   /**
     233                 :             :    * @brief Flush all outputs
     234                 :             :    */
     235                 :             :   void flush();
     236                 :             : 
     237                 :             :   // Main logging functions
     238                 :             :   void log(LogLevel level, std::string_view component, std::string_view operation, std::string_view message,
     239                 :        1826 :            const std::source_location& loc = std::source_location::current());
     240                 :             : 
     241                 :             :   void debug(std::string_view component, std::string_view operation, std::string_view message,
     242                 :           1 :              const std::source_location& loc = std::source_location::current());
     243                 :             :   void info(std::string_view component, std::string_view operation, std::string_view message,
     244                 :           1 :             const std::source_location& loc = std::source_location::current());
     245                 :             :   void warning(std::string_view component, std::string_view operation, std::string_view message,
     246                 :           1 :                const std::source_location& loc = std::source_location::current());
     247                 :             :   void error(std::string_view component, std::string_view operation, std::string_view message,
     248                 :           1 :              const std::source_location& loc = std::source_location::current());
     249                 :             :   void critical(std::string_view component, std::string_view operation, std::string_view message,
     250                 :           2 :                 const std::source_location& loc = std::source_location::current());
     251                 :             : 
     252                 :             :  private:
     253                 :             :   struct Impl;
     254                 :        2917 :   const Impl* get_impl() const { return impl_.get(); }
     255                 :             :   Impl* get_impl() { return impl_.get(); }
     256                 :             :   std::unique_ptr<Impl> impl_;
     257                 :             : };
     258                 :             : 
     259                 :             : /**
     260                 :             :  * @brief Convenience macros for logging
     261                 :             :  */
     262                 :             : #define WIRESTEAD_LOG(level, component, operation, message)                                               \
     263                 :             :   do {                                                                                                    \
     264                 :             :     const auto wirestead_log_level = (level);                                                             \
     265                 :             :     if (wirestead::diagnostics::Logger::instance().should_log(wirestead_log_level)) {                     \
     266                 :             :       wirestead::diagnostics::Logger::instance().log(wirestead_log_level, component, operation, message); \
     267                 :             :     }                                                                                                     \
     268                 :             :   } while (0)
     269                 :             : 
     270                 :             : #define WIRESTEAD_LOG_DEBUG(component, operation, message) \
     271                 :             :   WIRESTEAD_LOG(wirestead::diagnostics::LogLevel::DEBUG, component, operation, message)
     272                 :             : 
     273                 :             : #define WIRESTEAD_LOG_INFO(component, operation, message) \
     274                 :             :   WIRESTEAD_LOG(wirestead::diagnostics::LogLevel::INFO, component, operation, message)
     275                 :             : 
     276                 :             : #define WIRESTEAD_LOG_WARNING(component, operation, message) \
     277                 :             :   WIRESTEAD_LOG(wirestead::diagnostics::LogLevel::WARNING, component, operation, message)
     278                 :             : 
     279                 :             : #define WIRESTEAD_LOG_ERROR(component, operation, message) \
     280                 :             :   WIRESTEAD_LOG(wirestead::diagnostics::LogLevel::ERROR, component, operation, message)
     281                 :             : 
     282                 :             : #define WIRESTEAD_LOG_CRITICAL(component, operation, message) \
     283                 :             :   WIRESTEAD_LOG(wirestead::diagnostics::LogLevel::CRITICAL, component, operation, message)
     284                 :             : 
     285                 :             : /**
     286                 :             :  * @brief Performance logging macros for expensive operations.
     287                 :             :  *
     288                 :             :  * Usage: WIRESTEAD_LOG_PERF_START and WIRESTEAD_LOG_PERF_END must use the same
     289                 :             :  * `component` and `operation` tokens, and each `operation` token must be
     290                 :             :  * unique within its enclosing scope (the token becomes part of a variable name).
     291                 :             :  */
     292                 :             : #define WIRESTEAD_LOG_PERF_START(component, operation)                                                 \
     293                 :             :   auto _perf_start_##operation =                                                                       \
     294                 :             :       (wirestead::diagnostics::Logger::instance().should_log(wirestead::diagnostics::LogLevel::DEBUG)) \
     295                 :             :           ? std::chrono::high_resolution_clock::now()                                                  \
     296                 :             :           : std::chrono::high_resolution_clock::time_point()
     297                 :             : 
     298                 :             : #define WIRESTEAD_LOG_PERF_END(component, operation)                                                      \
     299                 :             :   do {                                                                                                    \
     300                 :             :     if (wirestead::diagnostics::Logger::instance().should_log(wirestead::diagnostics::LogLevel::DEBUG)) { \
     301                 :             :       auto _perf_end_##operation = std::chrono::high_resolution_clock::now();                             \
     302                 :             :       using _us_t = std::chrono::microseconds;                                                            \
     303                 :             :       auto _diff_##operation = _perf_end_##operation - _perf_start_##operation;                           \
     304                 :             :       auto _perf_duration_##operation = std::chrono::duration_cast<_us_t>(_diff_##operation).count();     \
     305                 :             :       WIRESTEAD_LOG(wirestead::diagnostics::LogLevel::DEBUG, component, operation,                        \
     306                 :             :                     "Duration: " + std::to_string(_perf_duration_##operation) + " μs");                   \
     307                 :             :     }                                                                                                     \
     308                 :             :   } while (0)
     309                 :             : 
     310                 :             : #define UNILINK_LOG(level, component, operation, message) WIRESTEAD_LOG(level, component, operation, message)
     311                 :             : 
     312                 :             : #define UNILINK_LOG_DEBUG(component, operation, message) WIRESTEAD_LOG_DEBUG(component, operation, message)
     313                 :             : 
     314                 :             : #define UNILINK_LOG_INFO(component, operation, message) WIRESTEAD_LOG_INFO(component, operation, message)
     315                 :             : 
     316                 :             : #define UNILINK_LOG_WARNING(component, operation, message) WIRESTEAD_LOG_WARNING(component, operation, message)
     317                 :             : 
     318                 :             : #define UNILINK_LOG_ERROR(component, operation, message) WIRESTEAD_LOG_ERROR(component, operation, message)
     319                 :             : 
     320                 :             : #define UNILINK_LOG_CRITICAL(component, operation, message) WIRESTEAD_LOG_CRITICAL(component, operation, message)
     321                 :             : 
     322                 :             : #define UNILINK_LOG_PERF_START(component, operation) WIRESTEAD_LOG_PERF_START(component, operation)
     323                 :             : 
     324                 :             : #define UNILINK_LOG_PERF_END(component, operation) WIRESTEAD_LOG_PERF_END(component, operation)
     325                 :             : 
     326                 :             : }  // namespace diagnostics
     327                 :             : }  // namespace wirestead
        

Generated by: LCOV version 2.0-1