| #include "tlbmc/hal/shared_mem/metrics.h" |
| |
| #include <sys/stat.h> |
| |
| #include <algorithm> |
| #include <atomic> |
| #include <cstddef> |
| #include <cstdint> |
| #include <functional> |
| #include <iterator> |
| #include <limits> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| |
| #include "absl/container/btree_set.h" |
| #include "absl/strings/substitute.h" |
| #include "absl/time/time.h" |
| #include "nlohmann/json.hpp" |
| #include "pattern_to_entity_array.h" |
| #include "bmcweb_authorizer_singleton.h" |
| |
| namespace milotic_tlbmc { |
| |
| using ::milotic::authz::BmcWebAuthorizerSingleton; |
| using ::milotic::authz::pattern_entity_pair_array; |
| |
| void TlbmcMetrics::UpdateMetricsRequestCount(bool is_tlbmc_request) { |
| if (is_tlbmc_request) { |
| total_tlbmc_request_count_.fetch_add(1, std::memory_order_relaxed); |
| } else { |
| total_gbmcweb_request_count_.fetch_add(1, std::memory_order_relaxed); |
| } |
| } |
| |
| void TlbmcMetrics::UpdateMetricsResponse(absl::Duration response_time, |
| int status_code, |
| std::string_view resource_url) { |
| // Update response status code count. |
| bool supported_status_code = std::binary_search( |
| kSupportedStatusCodes.begin(), kSupportedStatusCodes.end(), status_code); |
| if (supported_status_code) { |
| response_status_code_count_[status_code].fetch_add( |
| 1, std::memory_order_relaxed); |
| } else { |
| response_status_code_count_[kMaxResponseStatusCode].fetch_add( |
| 1, std::memory_order_relaxed); |
| } |
| |
| // Update response time histogram. |
| int64_t bucket_index = response_time / kResponseTimeHistogramBucketTime; |
| if (bucket_index >= kResponseTimeHistogramBucketCount) { |
| bucket_index = 19; |
| } |
| response_time_histogram_[bucket_index].fetch_add(1, |
| std::memory_order_relaxed); |
| |
| size_t index = |
| BmcWebAuthorizerSingleton::GetInstance().GetNodeIndexInPatternArray( |
| resource_url); |
| if (index != std::numeric_limits<std::size_t>::max()) { |
| MetricsIntegerType response_time_ms = |
| static_cast<MetricsIntegerType>(response_time / absl::Milliseconds(1)); |
| response_total_latency_ms_per_resource_[index].fetch_add( |
| response_time_ms, std::memory_order_relaxed); |
| total_response_count_per_resource_[index].fetch_add( |
| 1, std::memory_order_relaxed); |
| } |
| } |
| |
| nlohmann::json TlbmcMetrics::ToJson() const { |
| nlohmann::json json; |
| json["TotalTlbmcRequestCount"] = total_tlbmc_request_count_.load(); |
| json["TotalGbmcwebRequestCount"] = total_gbmcweb_request_count_.load(); |
| // Response status code count. |
| nlohmann::json::array_t response_status_code_count_json; |
| for (int code : kSupportedStatusCodes) { |
| nlohmann::json response_status_code_pair; |
| response_status_code_pair["ResponseStatusCode"] = std::to_string(code); |
| response_status_code_pair["Count"] = |
| response_status_code_count_[code].load(); |
| response_status_code_count_json.push_back(response_status_code_pair); |
| } |
| nlohmann::json response_status_code_pair; |
| response_status_code_pair["ResponseStatusCode"] = |
| std::to_string(kMaxResponseStatusCode); |
| response_status_code_pair["Count"] = |
| response_status_code_count_[kMaxResponseStatusCode].load(); |
| response_status_code_count_json.push_back(response_status_code_pair); |
| json["ResponseStatusCodeCount"] = response_status_code_count_json; |
| // Response time histogram. |
| nlohmann::json::array_t response_time_histogram_json; |
| for (int i = 0; i < kResponseTimeHistogramBucketCount; ++i) { |
| nlohmann::json response_time_histogram_pair; |
| std::string bucket_name; |
| if (i != kResponseTimeHistogramBucketCount - 1) { |
| bucket_name = absl::Substitute("$0ms", (i + 1) * 50 - 1); |
| } else { |
| bucket_name = "inf"; |
| } |
| response_time_histogram_pair["ResponseTime"] = bucket_name; |
| response_time_histogram_pair["Count"] = response_time_histogram_[i].load(); |
| response_time_histogram_json.push_back(response_time_histogram_pair); |
| } |
| json["ResponseTimeHistogram"] = response_time_histogram_json; |
| // Top latency resources. |
| // Find the top k resources with the highest average latency. |
| absl::btree_set<std::pair<float, int>, std::greater<>> top_latency_resources; |
| for (int i = 0; i < kResourceCount; ++i) { |
| MetricsIntegerType total_latency_ms = |
| response_total_latency_ms_per_resource_[i].load(); |
| MetricsIntegerType total_response_count = |
| total_response_count_per_resource_[i].load(); |
| if (total_response_count > 0) { |
| top_latency_resources.insert( |
| {static_cast<float>(total_latency_ms) / |
| static_cast<float>(total_response_count), |
| i}); |
| if (top_latency_resources.size() > kTopLatencyResourcesCount) { |
| top_latency_resources.erase(std::prev(top_latency_resources.end())); |
| } |
| } |
| } |
| // Insert the top k resources into the json. |
| nlohmann::json::array_t top_latency_resources_json; |
| for (const auto& [average_latency_ms, index] : top_latency_resources) { |
| nlohmann::json resource_latency_pair; |
| resource_latency_pair["Name"] = |
| std::string(pattern_entity_pair_array[index].first); |
| resource_latency_pair["Latency"] = |
| absl::Substitute("$0ms", average_latency_ms); |
| top_latency_resources_json.push_back(resource_latency_pair); |
| } |
| json["TopLatencyResources"] = top_latency_resources_json; |
| return json; |
| } |
| |
| } // namespace milotic_tlbmc |