unilink  0.4.3
A simple C++ library for unified async communication
error_types.hpp
Go to the documentation of this file.
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 <algorithm>
20 #include <boost/system/error_code.hpp>
21 #include <chrono>
22 #include <cstdint>
23 #include <ctime>
24 #include <iomanip>
25 #include <sstream>
26 #include <string>
27 #include <string_view>
28 
29 namespace unilink {
30 namespace diagnostics {
31 
32 #ifdef ERROR
33 #undef ERROR
34 #endif
35 #ifdef WARNING
36 #undef WARNING
37 #endif
38 
42 enum class ErrorLevel {
43  INFO = 0, // Informational message (normal operation info)
44  WARNING = 1, // Warning (recoverable issue)
45  ERROR = 2, // Error (retry required)
46  CRITICAL = 3 // Critical error (unrecoverable)
47 };
48 
52 enum class ErrorCategory {
53  CONNECTION = 0, // Connection related (TCP, Serial connect/disconnect)
54  COMMUNICATION = 1, // Communication related (data send/receive)
55  CONFIGURATION = 2, // Configuration related (invalid config values)
56  MEMORY = 3, // Memory related (allocation/deallocation errors)
57  SYSTEM = 4, // System related (OS level errors)
58  UNKNOWN = 5 // Unknown error
59 };
60 
64 struct ErrorInfo {
65  ErrorLevel level; // Error severity
66  ErrorCategory category; // Error category
67  std::string component; // Component name (serial, tcp_server, tcp_client)
68  std::string operation; // Operation being performed (read, write, connect, bind)
69  std::string message; // Error message
70  boost::system::error_code boost_error; // Boost error code
71  std::chrono::system_clock::time_point timestamp; // Error occurrence time
72  bool retryable; // Retry possibility
73  uint32_t retry_count; // Current retry count
74  std::string context; // Additional context information
75 
79  ErrorInfo(ErrorLevel l, ErrorCategory c, std::string_view comp, std::string_view op, std::string_view msg)
80  : level(l),
81  category(c),
82  component(comp),
83  operation(op),
84  message(msg),
85  timestamp(std::chrono::system_clock::now()),
86  retryable(false),
87  retry_count(0) {}
88 
92  ErrorInfo(ErrorLevel l, ErrorCategory c, std::string_view comp, std::string_view op, std::string_view msg,
93  const boost::system::error_code& ec, bool retry = false)
94  : level(l),
95  category(c),
96  component(comp),
97  operation(op),
98  message(msg),
99  boost_error(ec),
100  timestamp(std::chrono::system_clock::now()),
101  retryable(retry),
102  retry_count(0) {}
103 
107  std::string get_timestamp_string() const {
108  auto time_t = std::chrono::system_clock::to_time_t(timestamp);
109  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(timestamp.time_since_epoch()) % 1000;
110 
111  std::tm tm_buf{};
112 #if defined(_MSC_VER)
113  localtime_s(&tm_buf, &time_t);
114 #else
115  localtime_r(&time_t, &tm_buf);
116 #endif
117 
118  std::ostringstream oss;
119  oss << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S");
120  oss << '.' << std::setfill('0') << std::setw(3) << ms.count();
121  return oss.str();
122  }
123 
127  std::string get_level_string() const {
128  switch (level) {
129  case ErrorLevel::INFO:
130  return "INFO";
131  case ErrorLevel::WARNING:
132  return "WARNING";
133  case ErrorLevel::ERROR:
134  return "ERROR";
136  return "CRITICAL";
137  }
138  return "UNKNOWN";
139  }
140 
144  std::string get_category_string() const {
145  switch (category) {
147  return "CONNECTION";
149  return "COMMUNICATION";
151  return "CONFIGURATION";
153  return "MEMORY";
155  return "SYSTEM";
157  return "UNKNOWN";
158  }
159  return "UNKNOWN";
160  }
161 
165  std::string get_summary() const {
166  std::ostringstream oss;
167  oss << "[" << get_level_string() << "] " << "[" << component << "] " << "[" << operation << "] " << message;
168 
169  if (boost_error) {
170  oss << " (boost: " << boost_error.message() << ", code: " << boost_error.value() << ")";
171  }
172 
173  if (retryable) {
174  oss << " [RETRYABLE, count: " << retry_count << "]";
175  }
176 
177  return oss.str();
178  }
179 };
180 
184 struct ErrorStats {
185  size_t total_errors = 0;
186  size_t errors_by_level[4] = {0, 0, 0, 0}; // INFO, WARNING, ERROR, CRITICAL
187  size_t errors_by_category[6] = {0, 0, 0, 0, 0, 0}; // CONNECTION, COMMUNICATION, etc.
188  size_t retryable_errors = 0;
189  size_t successful_retries = 0;
190  size_t failed_retries = 0;
191 
192  std::chrono::system_clock::time_point first_error;
193  std::chrono::system_clock::time_point last_error;
194 
198  void reset() {
199  total_errors = 0;
200  std::fill(std::begin(errors_by_level), std::end(errors_by_level), 0);
201  std::fill(std::begin(errors_by_category), std::end(errors_by_category), 0);
202  retryable_errors = 0;
203  successful_retries = 0;
204  failed_retries = 0;
205  first_error = std::chrono::system_clock::time_point{};
206  last_error = std::chrono::system_clock::time_point{};
207  }
208 
212  double get_error_rate() const {
213  if (total_errors == 0) return 0.0;
214 
215  auto duration = std::chrono::duration_cast<std::chrono::minutes>(last_error - first_error).count();
216  return duration > 0 ? static_cast<double>(total_errors) / static_cast<double>(duration) : 0.0;
217  }
218 };
219 
220 } // namespace diagnostics
221 } // namespace unilink