-
Notifications
You must be signed in to change notification settings - Fork 110
[k2] add metrics builder and k2_write_metric API #1639
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -97,6 +97,20 @@ enum UpdateStatus { | |
| NewDescriptor = 2, | ||
| }; | ||
|
|
||
| enum MonitoringSystem { StatsHouse }; | ||
|
|
||
| /* | ||
| * Serialized metric format: | ||
| * <timestamp_u32><value_format><msg_size><metric_name_len><metric_name><tag1_name_len><tag1_name><tag1_value_len><tag1_value>... | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is |
||
| * | ||
| * value_format: | ||
| * <VALUE_MASK><f64> - single float value | ||
| * <VALUES_ARRAY_MASK><array_len><f64_1><f64_2>... - array of float values | ||
| * <COUNT_MASK><f64> - count value | ||
| * <INC_MASK> - counter increment (no payload) | ||
| */ | ||
| enum MetricValueMask : uint8_t { VALUE_MASK = 0, VALUES_ARRAY_MASK = 1, COUNT_MASK = 2, INC_MASK = 3 }; | ||
|
|
||
| struct ImageInfo { | ||
| // Base | ||
| const char* image_name; | ||
|
|
@@ -383,6 +397,17 @@ void* k2_mmap(uint64_t* md, void* addr, size_t length, int32_t prot, int32_t fla | |
| */ | ||
| int32_t k2_madvise(void* addr, size_t length, int32_t advise); | ||
|
|
||
| /** | ||
| * Writes a pre-serialized metric to the specified monitoring system. | ||
| * The buffer must contain a metric serialized according to the format described above | ||
| * (see `MetricValueMask` and the serialized metric format comment). | ||
| * | ||
| * @param `buf` A pointer to the serialized metric data. | ||
| * @param `buf_len` The length of the serialized metric data in bytes. | ||
| * @param `ms` The target monitoring system. | ||
| */ | ||
| void k2_write_metric(const uint8_t* buf, size_t buf_len, enum MonitoringSystem ms); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| /** | ||
| * Sets `StreamStatus.please_whutdown_write=true` for the component on the | ||
| * opposite side (does not affect `StreamStatus` on your side). | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| // Compiler for PHP (aka KPHP) | ||
| // Copyright (c) 2026 LLC «V Kontakte» | ||
| // Distributed under the GPL v3 License, see LICENSE.notice.txt | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <chrono> | ||
| #include <cstddef> | ||
| #include <cstdint> | ||
|
|
||
| #include "common/mixin/movable_only.h" | ||
| #include "runtime-common/core/allocator/script-allocator.h" | ||
| #include "runtime-common/core/std/containers.h" | ||
| #include "runtime-light/k2-platform/k2-api.h" | ||
|
|
||
| struct MetricBuilder final : vk::movable_only { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's put it in |
||
| private: | ||
| using bytes_vector = kphp::stl::vector<uint8_t, kphp::memory::script_allocator>; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks a bit weird that you use private type in public API of |
||
|
|
||
| std::string metric_name; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can't use |
||
| kphp::stl::unordered_map<std::string, std::string, kphp::memory::script_allocator> tags; | ||
| size_t msg_size{0}; | ||
|
|
||
| explicit MetricBuilder(std::string_view metric_name) noexcept | ||
| : metric_name{metric_name} { | ||
| this->msg_size += MetricBuilder::string_sizeof(metric_name); | ||
| } | ||
|
|
||
| template<typename T> | ||
| requires std::is_arithmetic_v<T> | ||
| static void store_number(bytes_vector& buf, const T& number) noexcept { | ||
| const auto* src = static_cast<const uint8_t*>(static_cast<const void*>(&number)); | ||
| buf.insert(buf.end(), src, src + sizeof(T)); | ||
| } | ||
|
|
||
| static void store_string(bytes_vector& buf, const std::string_view& string) noexcept { | ||
| MetricBuilder::store_number(buf, string.size()); | ||
| buf.insert(buf.end(), string.begin(), string.end()); | ||
| } | ||
|
|
||
| void store_msg(bytes_vector& buf) const noexcept { | ||
| MetricBuilder::store_number(buf, this->msg_size); | ||
| MetricBuilder::store_string(buf, std::string_view{this->metric_name.c_str(), this->metric_name.size()}); | ||
| for (const auto& [tag_name, tag_value] : this->tags) { | ||
| MetricBuilder::store_string(buf, std::string_view{tag_name.c_str(), tag_name.size()}); | ||
| MetricBuilder::store_string(buf, std::string_view{tag_value.c_str(), tag_value.size()}); | ||
| } | ||
| } | ||
|
|
||
| static size_t string_sizeof(const std::string_view& string) noexcept { | ||
| return sizeof(size_t) + string.size(); | ||
| } | ||
|
|
||
| static uint32_t s_timestamp_now() noexcept { | ||
| return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count(); | ||
| } | ||
|
|
||
| public: | ||
| static MetricBuilder metric(std::string_view metric_name) noexcept { | ||
| return MetricBuilder{metric_name}; | ||
| } | ||
|
|
||
| MetricBuilder& tag(std::string_view tag_name, std::string_view tag_value) noexcept { | ||
| this->tags[std::string{tag_name}] = std::string{tag_value}; | ||
| this->msg_size += MetricBuilder::string_sizeof(tag_name) + MetricBuilder::string_sizeof(tag_value); | ||
| return *this; | ||
| } | ||
|
|
||
| bytes_vector build_value(double value, std::optional<uint32_t> timestamp = std::nullopt) const noexcept { | ||
| bytes_vector buf{}; | ||
| buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + | ||
| this->msg_size); // timestamp_u32 + value_mask_u8 + value_f64 + msg_size_usize + msg_len | ||
|
|
||
| uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; | ||
|
|
||
| MetricBuilder::store_number(buf, s_timestamp); | ||
| MetricBuilder::store_number(buf, static_cast<uint8_t>(k2::MetricValueMask::VALUE_MASK)); | ||
| MetricBuilder::store_number(buf, value); | ||
| this->store_msg(buf); | ||
| return buf; | ||
| } | ||
|
|
||
| bytes_vector build_values_array(const kphp::stl::vector<double, kphp::memory::script_allocator>& values, | ||
| std::optional<uint32_t> timestamp = std::nullopt) const noexcept { | ||
| bytes_vector buf{}; | ||
| buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + | ||
| this->msg_size); // timestamp_u32 + value_mask_u8 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len | ||
|
|
||
| uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; | ||
|
|
||
| MetricBuilder::store_number(buf, s_timestamp); | ||
| MetricBuilder::store_number(buf, static_cast<uint8_t>(k2::MetricValueMask::VALUES_ARRAY_MASK)); | ||
| MetricBuilder::store_number(buf, values.size()); | ||
| for (const auto& value : values) { | ||
| MetricBuilder::store_number(buf, value); | ||
| } | ||
| this->store_msg(buf); | ||
| return buf; | ||
| } | ||
|
|
||
| bytes_vector build_count(double count, std::optional<uint32_t> timestamp = std::nullopt) const noexcept { | ||
| bytes_vector buf{}; | ||
| buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + | ||
| this->msg_size); // timestamp_u32 + value_mask_u8 + count_f64 + msg_size_usize + msg_len | ||
|
|
||
| uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; | ||
|
|
||
| MetricBuilder::store_number(buf, s_timestamp); | ||
| MetricBuilder::store_number(buf, static_cast<uint8_t>(k2::MetricValueMask::COUNT_MASK)); | ||
| MetricBuilder::store_number(buf, count); | ||
| this->store_msg(buf); | ||
| return buf; | ||
| } | ||
|
|
||
| bytes_vector build_increment(std::optional<uint32_t> timestamp = std::nullopt) const noexcept { | ||
| bytes_vector buf{}; | ||
| buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_mask_u8 + msg_size_usize + msg_len | ||
|
|
||
| uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; | ||
|
|
||
| MetricBuilder::store_number(buf, s_timestamp); | ||
| MetricBuilder::store_number(buf, static_cast<uint8_t>(k2::MetricValueMask::INC_MASK)); | ||
| this->store_msg(buf); | ||
| return buf; | ||
| } | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need vector here.
std::spanis enough