LCOV - code coverage report
Current view: top level - wirestead/diagnostics - error_handler.cc (source / functions) Coverage Total Hit
Test: Wirestead Coverage Report Lines: 100.0 % 133 133
Test Date: 2026-08-30 10:35:09 Functions: 100.0 % 29 29
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 89.3 % 28 25

             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                 :             : #include "wirestead/diagnostics/error_handler.hpp"
      18                 :             : 
      19                 :             : #include <algorithm>
      20                 :             : #include <iomanip>
      21                 :             : #include <iostream>
      22                 :             : #include <sstream>
      23                 :             : #include <string_view>
      24                 :             : 
      25                 :             : #include "wirestead/diagnostics/logger.hpp"
      26                 :             : 
      27                 :             : namespace wirestead {
      28                 :             : namespace diagnostics {
      29                 :             : 
      30                 :          37 : ErrorHandler::ErrorHandler() = default;
      31                 :          37 : ErrorHandler::~ErrorHandler() = default;
      32                 :             : 
      33                 :        1129 : ErrorHandler& ErrorHandler::instance() {
      34                 :        1129 :   static ErrorHandler inst;
      35                 :        1129 :   return inst;
      36                 :             : }
      37                 :             : 
      38                 :           1 : ErrorHandler& ErrorHandler::default_handler() { return instance(); }
      39                 :             : 
      40                 :        1084 : void ErrorHandler::report_error(const ErrorInfo& error) {
      41         [ +  + ]:        1084 :   if (!enabled_.load()) {
      42                 :           5 :     return;
      43                 :             :   }
      44                 :             : 
      45         [ +  + ]:        1082 :   if (error.level < min_level_.load()) {
      46                 :           3 :     return;
      47                 :             :   }
      48                 :             : 
      49                 :        1079 :   std::vector<ErrorCallback> callbacks_copy;
      50                 :             :   {
      51                 :        1079 :     std::lock_guard<std::mutex> lock(mutex_);
      52                 :        1079 :     update_stats(error);
      53                 :        1079 :     add_to_recent_errors(error);
      54                 :        1079 :     add_to_component_errors(error);
      55                 :        1079 :     callbacks_copy = callbacks_;
      56                 :        1079 :   }
      57                 :        1079 :   notify_callbacks(callbacks_copy, error);
      58                 :        1079 : }
      59                 :             : 
      60                 :           9 : void ErrorHandler::register_callback(ErrorCallback callback) {
      61                 :           9 :   std::lock_guard<std::mutex> lock(mutex_);
      62                 :           9 :   callbacks_.push_back(std::move(callback));
      63                 :           9 : }
      64                 :             : 
      65                 :          27 : void ErrorHandler::clear_callbacks() {
      66                 :          27 :   std::lock_guard<std::mutex> lock(mutex_);
      67                 :          27 :   callbacks_.clear();
      68                 :          27 : }
      69                 :             : 
      70                 :          24 : void ErrorHandler::set_min_error_level(ErrorLevel level) { min_level_.store(level); }
      71                 :             : 
      72                 :           1 : ErrorLevel ErrorHandler::min_error_level() const { return min_level_.load(); }
      73                 :             : 
      74                 :          26 : void ErrorHandler::set_enabled(bool enabled) { enabled_.store(enabled); }
      75                 :             : 
      76                 :           2 : bool ErrorHandler::enabled() const { return enabled_.load(); }
      77                 :             : 
      78                 :          15 : ErrorStats ErrorHandler::error_stats() const {
      79                 :          15 :   std::lock_guard<std::mutex> lock(stats_mutex_);
      80                 :          15 :   return stats_;
      81                 :          15 : }
      82                 :             : 
      83                 :          23 : void ErrorHandler::reset_stats() {
      84                 :          23 :   std::lock_guard<std::mutex> lock(stats_mutex_);
      85                 :          23 :   stats_.reset();
      86                 :          23 : }
      87                 :             : 
      88                 :           3 : std::vector<ErrorInfo> ErrorHandler::errors_by_component(std::string_view component) const {
      89                 :           3 :   std::lock_guard<std::mutex> lock(mutex_);
      90                 :           6 :   auto it = errors_by_component_.find(std::string(component));
      91         [ +  + ]:           3 :   if (it != errors_by_component_.end()) {
      92                 :           2 :     return it->second;
      93                 :             :   }
      94                 :           1 :   return {};
      95                 :           3 : }
      96                 :             : 
      97                 :           2 : std::vector<ErrorInfo> ErrorHandler::recent_errors(size_t count) const {
      98                 :           2 :   std::lock_guard<std::mutex> lock(mutex_);
      99                 :             : 
     100                 :           2 :   size_t start_index = 0;
     101         [ +  + ]:           2 :   if (recent_errors_.size() > count) {
     102                 :           1 :     start_index = recent_errors_.size() - count;
     103                 :             :   }
     104                 :             : 
     105                 :           2 :   return std::vector<ErrorInfo>(recent_errors_.begin() + static_cast<std::ptrdiff_t>(start_index),
     106                 :           4 :                                 recent_errors_.end());
     107                 :           2 : }
     108                 :             : 
     109                 :           2 : bool ErrorHandler::has_errors(std::string_view component) const {
     110                 :           2 :   std::lock_guard<std::mutex> lock(mutex_);
     111                 :           4 :   auto it = errors_by_component_.find(std::string(component));
     112   [ +  +  +  - ]:           4 :   return it != errors_by_component_.end() && !it->second.empty();
     113                 :           2 : }
     114                 :             : 
     115                 :           5 : size_t ErrorHandler::error_count(std::string_view component, ErrorLevel level) const {
     116                 :           5 :   std::lock_guard<std::mutex> lock(mutex_);
     117                 :          10 :   auto it = errors_by_component_.find(std::string(component));
     118         [ +  + ]:           5 :   if (it == errors_by_component_.end()) {
     119                 :           1 :     return 0;
     120                 :             :   }
     121                 :             : 
     122         [ +  - ]:           4 :   return static_cast<size_t>(std::count_if(it->second.begin(), it->second.end(),
     123                 :          16 :                                            [level](const ErrorInfo& error) { return error.level == level; }));
     124                 :           5 : }
     125                 :             : 
     126                 :        1079 : void ErrorHandler::update_stats(const ErrorInfo& error) {
     127                 :        1079 :   std::lock_guard<std::mutex> lock(stats_mutex_);
     128                 :             : 
     129                 :        1079 :   stats_.total_errors++;
     130                 :        1079 :   stats_.errors_by_level[static_cast<int>(error.level)]++;
     131                 :        1079 :   stats_.errors_by_category[static_cast<int>(error.category)]++;
     132                 :             : 
     133         [ +  + ]:        1079 :   if (error.retryable) {
     134                 :          29 :     stats_.retryable_errors++;
     135                 :             :   }
     136                 :             : 
     137   [ +  -  +  + ]:        1079 :   if (stats_.first_error == std::chrono::system_clock::time_point{}) {
     138                 :          35 :     stats_.first_error = error.timestamp;
     139                 :             :   }
     140                 :        1079 :   stats_.last_error = error.timestamp;
     141                 :        1079 : }
     142                 :             : 
     143                 :        1079 : void ErrorHandler::notify_callbacks(const std::vector<ErrorCallback>& callbacks, const ErrorInfo& error) {
     144         [ +  + ]:        1090 :   for (const auto& callback : callbacks) {
     145                 :             :     try {
     146                 :          11 :       callback(error);
     147                 :           2 :     } catch (const std::exception& e) {
     148                 :             :       // Avoid infinite recursion - use Logger directly instead of ErrorHandler
     149                 :           3 :       WIRESTEAD_LOG_ERROR("error_handler", "callback", "Error in error callback: " + std::string(e.what()));
     150                 :           2 :     } catch (...) {
     151                 :           1 :       WIRESTEAD_LOG_ERROR("error_handler", "callback", "Unknown error in error callback");
     152                 :           1 :     }
     153                 :             :   }
     154                 :        1079 : }
     155                 :             : 
     156                 :        1079 : void ErrorHandler::add_to_recent_errors(const ErrorInfo& error) {
     157                 :        1079 :   recent_errors_.push_back(error);
     158                 :             : 
     159                 :             :   // Keep only the most recent errors
     160         [ +  + ]:        1079 :   if (recent_errors_.size() > MAX_RECENT_ERRORS) {
     161                 :          10 :     recent_errors_.erase(
     162                 :           5 :         recent_errors_.begin(),
     163                 :          10 :         recent_errors_.begin() + static_cast<std::ptrdiff_t>(recent_errors_.size() - MAX_RECENT_ERRORS));
     164                 :             :   }
     165                 :        1079 : }
     166                 :             : 
     167                 :        1079 : void ErrorHandler::add_to_component_errors(const ErrorInfo& error) {
     168                 :        1079 :   errors_by_component_[error.component].push_back(error);
     169                 :             : 
     170                 :             :   // Limit component error history to prevent memory growth
     171                 :        1079 :   constexpr size_t MAX_COMPONENT_ERRORS = 100;
     172                 :        1079 :   auto& component_errors = errors_by_component_[error.component];
     173         [ +  + ]:        1079 :   if (component_errors.size() > MAX_COMPONENT_ERRORS) {
     174                 :        1810 :     component_errors.erase(
     175                 :         905 :         component_errors.begin(),
     176                 :        1810 :         component_errors.begin() + static_cast<std::ptrdiff_t>(component_errors.size() - MAX_COMPONENT_ERRORS));
     177                 :             :   }
     178                 :        1079 : }
     179                 :             : 
     180                 :             : // Convenience functions implementation
     181                 :             : namespace error_reporting {
     182                 :             : 
     183                 :          54 : void report_connection_error(std::string_view component, std::string_view operation,
     184                 :             :                              const boost::system::error_code& ec, bool retryable) {
     185                 :          54 :   ErrorInfo error(ErrorLevel::ERROR, ErrorCategory::CONNECTION, component, operation, ec.message(), ec, retryable);
     186                 :          54 :   ErrorHandler::instance().report_error(error);
     187                 :          54 : }
     188                 :             : 
     189                 :           1 : void report_communication_error(std::string_view component, std::string_view operation, std::string_view message,
     190                 :             :                                 bool retryable) {
     191                 :           1 :   ErrorInfo error(ErrorLevel::ERROR, ErrorCategory::COMMUNICATION, component, operation, message);
     192                 :           1 :   error.retryable = retryable;
     193                 :           1 :   ErrorHandler::instance().report_error(error);
     194                 :           1 : }
     195                 :             : 
     196                 :           6 : void report_configuration_error(std::string_view component, std::string_view operation, std::string_view message) {
     197                 :           6 :   ErrorInfo error(ErrorLevel::ERROR, ErrorCategory::CONFIGURATION, component, operation, message);
     198                 :           6 :   ErrorHandler::instance().report_error(error);
     199                 :           6 : }
     200                 :             : 
     201                 :           6 : void report_memory_error(std::string_view component, std::string_view operation, std::string_view message) {
     202                 :           6 :   ErrorInfo error(ErrorLevel::CRITICAL, ErrorCategory::MEMORY, component, operation, message);
     203                 :           6 :   ErrorHandler::instance().report_error(error);
     204                 :           6 : }
     205                 :             : 
     206                 :           2 : void report_system_error(std::string_view component, std::string_view operation, std::string_view message,
     207                 :             :                          const boost::system::error_code& ec) {
     208                 :           2 :   ErrorInfo error(ErrorLevel::ERROR, ErrorCategory::SYSTEM, component, operation, message, ec);
     209                 :           2 :   ErrorHandler::instance().report_error(error);
     210                 :           2 : }
     211                 :             : 
     212                 :           3 : void report_warning(std::string_view component, std::string_view operation, std::string_view message) {
     213                 :           3 :   ErrorInfo error(ErrorLevel::WARNING, ErrorCategory::UNKNOWN, component, operation, message);
     214                 :           3 :   ErrorHandler::instance().report_error(error);
     215                 :           3 : }
     216                 :             : 
     217                 :        1012 : void report_info(std::string_view component, std::string_view operation, std::string_view message) {
     218                 :        1012 :   ErrorInfo error(ErrorLevel::INFO, ErrorCategory::UNKNOWN, component, operation, message);
     219                 :        1012 :   ErrorHandler::instance().report_error(error);
     220                 :        1012 : }
     221                 :             : 
     222                 :             : }  // namespace error_reporting
     223                 :             : 
     224                 :             : }  // namespace diagnostics
     225                 :             : }  // namespace wirestead
        

Generated by: LCOV version 2.0-1