Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
fallback_monitoring_backend.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
6
7#include <algorithm>
8#include <numeric>
9#include <sstream>
10
11namespace
12{
13 inline common::VoidResult make_error(const std::string& msg)
14 {
15 return common::VoidResult(common::error_info{ -1, msg, "" });
16 }
17
18 template<typename T>
19 common::Result<T> make_error_result(const std::string& msg)
20 {
21 return common::Result<T>(common::error_info{ -1, msg, "" });
22 }
23}
24
25namespace database
26{
27namespace integrated
28{
29namespace adapters
30{
31namespace backends
32{
33
35 : config_(config), initialized_(false)
36{
37}
38
46
48{
49 if (initialized_)
50 {
51 return common::ok();
52 }
53
54 start_time_ = std::chrono::steady_clock::now();
55 initialized_ = true;
56 return common::ok();
57}
58
60{
61 if (!initialized_)
62 {
63 return common::ok();
64 }
65
66 std::lock_guard<std::mutex> lock(mutex_);
68 query_latencies_.clear();
69 generic_metrics_.clear();
70 initialized_ = false;
71 return common::ok();
72}
73
78
80{
81 if (!initialized_)
82 {
83 return make_error("Monitoring backend not initialized");
84 }
85
86 std::lock_guard<std::mutex> lock(mutex_);
87 generic_metrics_[name] = value;
88 return common::ok();
89}
90
92 const std::string& name, double value,
93 const std::unordered_map<std::string, std::string>& /*tags*/)
94{
95 // Fallback ignores tags
96 return record_metric(name, value);
97}
98
100{
101 if (!initialized_)
102 {
103 return make_error_result<metrics_snapshot>("Monitoring backend not initialized");
104 }
105
106 std::lock_guard<std::mutex> lock(mutex_);
107
108 metrics_snapshot snapshot;
109 snapshot.source_id = "database_fallback";
110
111 // Connection metrics
112 snapshot.gauges["db.connections.active"] = static_cast<double>(metrics_.active_connections);
113 snapshot.gauges["db.connections.idle"] = static_cast<double>(metrics_.idle_connections);
114 snapshot.gauges["db.connections.usage_percent"] = metrics_.connection_usage_percent;
115
116 // Query metrics
117 snapshot.gauges["db.query.avg_latency_us"] = static_cast<double>(metrics_.avg_query_latency.count());
118 snapshot.gauges["db.query.success_rate"] = metrics_.query_success_rate;
119
120 snapshot.counters["db.queries.total"] = metrics_.total_queries;
121 snapshot.counters["db.queries.successful"] = metrics_.successful_queries;
122 snapshot.counters["db.queries.failed"] = metrics_.failed_queries;
123
124 // Transaction metrics
125 snapshot.counters["db.transactions.committed"] = metrics_.committed_transactions;
126 snapshot.counters["db.transactions.rolled_back"] = metrics_.rolled_back_transactions;
127
128 // Generic metrics
129 for (const auto& [name, value] : generic_metrics_)
130 {
131 snapshot.gauges[name] = value;
132 }
133
134 return snapshot;
135}
136
138{
139 if (!initialized_)
140 {
141 return make_error_result<health_check_result>("Monitoring backend not initialized");
142 }
143
144 std::lock_guard<std::mutex> lock(mutex_);
145
146 health_check_result result;
148 result.message = "Database system healthy";
149
150 // Connection pool health check
152 {
154 result.message = "Connection pool usage critical";
155 result.metadata["connection_usage"] = std::to_string(metrics_.connection_usage_percent) + "%";
156 }
157
158 // Query latency health check
160 {
162 result.message = "Query latency critical";
163 result.metadata["avg_latency_us"] = std::to_string(metrics_.avg_query_latency.count());
164 }
165
166 // Query success rate health check
168 {
170 result.message = "Query success rate low";
171 result.metadata["success_rate"] = std::to_string(metrics_.query_success_rate);
172 }
173
174 return result;
175}
176
178{
179 if (!initialized_)
180 {
181 return make_error("Monitoring backend not initialized");
182 }
183
184 std::lock_guard<std::mutex> lock(mutex_);
186 query_latencies_.clear();
187 generic_metrics_.clear();
188 return common::ok();
189}
190
191void fallback_monitoring_backend::record_query_execution(std::chrono::microseconds duration, bool success)
192{
193 std::lock_guard<std::mutex> lock(mutex_);
194
196 if (success)
197 {
199 }
200 else
201 {
203 }
204
205 if (metrics_.total_queries > 0)
206 {
208 }
209
210 query_latencies_.push_back(duration);
211
212 // Keep last 1000 samples
213 const size_t max_samples = 1000;
214 if (query_latencies_.size() > max_samples)
215 {
216 query_latencies_.erase(query_latencies_.begin());
217 }
218
220}
221
223{
224 // Handled by update_pool_stats
225}
226
228{
229 // Handled by update_pool_stats
230}
231
232void fallback_monitoring_backend::update_pool_stats(std::size_t active, std::size_t idle, std::size_t total)
233{
234 std::lock_guard<std::mutex> lock(mutex_);
235
239
240 if (total > 0)
241 {
242 metrics_.connection_usage_percent = (static_cast<double>(active) / total) * 100.0;
243 }
244}
245
247{
248 std::lock_guard<std::mutex> lock(mutex_);
250}
251
253{
254 std::lock_guard<std::mutex> lock(mutex_);
256 {
258 }
260}
261
263{
264 std::lock_guard<std::mutex> lock(mutex_);
266 {
268 }
270}
271
273{
274 if (!initialized_)
275 {
276 return make_error_result<database_metrics>("Monitoring backend not initialized");
277 }
278
279 std::lock_guard<std::mutex> lock(mutex_);
280 metrics_.timestamp = std::chrono::system_clock::now();
281 return metrics_;
282}
283
285{
286 std::lock_guard<std::mutex> lock(mutex_);
287
288 std::ostringstream oss;
289 oss << "# TYPE db_connections_active gauge\n";
290 oss << "db_connections_active " << metrics_.active_connections << "\n";
291
292 oss << "# TYPE db_connections_idle gauge\n";
293 oss << "db_connections_idle " << metrics_.idle_connections << "\n";
294
295 oss << "# TYPE db_queries_total counter\n";
296 oss << "db_queries_total " << metrics_.total_queries << "\n";
297
298 oss << "# TYPE db_queries_success_rate gauge\n";
299 oss << "db_queries_success_rate " << metrics_.query_success_rate << "\n";
300
301 oss << "# TYPE db_query_latency_avg_us gauge\n";
302 oss << "db_query_latency_avg_us " << metrics_.avg_query_latency.count() << "\n";
303
304 return oss.str();
305}
306
307std::chrono::microseconds fallback_monitoring_backend::calculate_percentile(double percentile)
308{
309 if (query_latencies_.empty())
310 {
311 return std::chrono::microseconds(0);
312 }
313
314 auto sorted = query_latencies_;
315 std::sort(sorted.begin(), sorted.end());
316
317 size_t idx = static_cast<size_t>(sorted.size() * percentile);
318 if (idx >= sorted.size())
319 {
320 idx = sorted.size() - 1;
321 }
322
323 return sorted[idx];
324}
325
327{
328 if (query_latencies_.empty())
329 {
330 return;
331 }
332
333 auto sum = std::accumulate(
334 query_latencies_.begin(), query_latencies_.end(), std::chrono::microseconds(0));
335 metrics_.avg_query_latency = std::chrono::microseconds(sum.count() / query_latencies_.size());
336
337 metrics_.min_query_latency = *std::min_element(query_latencies_.begin(), query_latencies_.end());
338 metrics_.max_query_latency = *std::max_element(query_latencies_.begin(), query_latencies_.end());
339
340 auto sorted = query_latencies_;
341 std::sort(sorted.begin(), sorted.end());
342
343 size_t p95_idx = static_cast<size_t>(sorted.size() * 0.95);
344 size_t p99_idx = static_cast<size_t>(sorted.size() * 0.99);
345
346 if (p95_idx < sorted.size())
347 {
348 metrics_.p95_query_latency = sorted[p95_idx];
349 }
350 if (p99_idx < sorted.size())
351 {
352 metrics_.p99_query_latency = sorted[p99_idx];
353 }
354}
355
356} // namespace backends
357} // namespace adapters
358} // namespace integrated
359} // namespace database
common::VoidResult initialize() override
Initialize the monitoring backend.
void update_pool_stats(std::size_t active, std::size_t idle, std::size_t total) override
Update connection pool statistics.
common::Result< metrics_snapshot > get_metrics() override
Get current metrics snapshot.
void record_query_execution(std::chrono::microseconds duration, bool success) override
Record query execution.
std::chrono::microseconds calculate_percentile(double percentile)
Calculate percentile from latency samples.
std::string export_prometheus_metrics() override
Export metrics in Prometheus format.
common::Result< database_metrics > get_database_metrics() override
Get database-specific metrics.
common::VoidResult shutdown() override
Shutdown the monitoring backend gracefully.
common::Result< health_check_result > check_health() override
Perform health check.
common::VoidResult record_metric(const std::string &name, double value) override
Record a metric value.
Fallback monitoring backend using internal metrics tracking.
VoidResult ok()
Result< std::monostate > VoidResult
async_result< T > make_error_result(const std::exception &error)
std::unordered_map< std::string, std::string > metadata
std::unordered_map< std::string, uint64_t > counters
std::uint64_t active_transactions
Currently active transactions.
std::size_t idle_connections
Idle connections in pool.
double connection_usage_percent
Percentage of connections in use.
std::size_t active_connections
Currently active connections.
std::uint64_t rolled_back_transactions
Total rolled-back transactions.
std::uint64_t total_queries
Total queries executed.
std::chrono::microseconds p99_query_latency
99th percentile latency
std::uint64_t successful_queries
Successfully completed queries.
std::chrono::system_clock::time_point timestamp
When metrics were collected.
std::chrono::microseconds p95_query_latency
95th percentile latency
std::chrono::microseconds max_query_latency
Maximum query latency.
std::chrono::microseconds avg_query_latency
Average query latency.
std::uint64_t committed_transactions
Total committed transactions.
std::chrono::microseconds min_query_latency
Minimum query latency.
Monitoring and metrics configuration.
std::chrono::milliseconds query_latency_warning
Warn when query latency exceeds this threshold.
double connection_usage_warning_threshold
Warn when connection pool usage exceeds this percentage (0.0-1.0)