blob: a6d72fbf0bc5d1e9947dfe267666e768419ec54c [file] [log] [blame]
#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