From 694884febce032c949b0bee54a558461b68d2ed4 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 19 Jun 2026 14:18:45 +0300 Subject: [PATCH 01/48] first version --- .../kphp-light/stdlib/output-functions.txt | 6 + runtime-light/k2-platform/k2-api.h | 14 ++ runtime-light/k2-platform/k2-header.h | 12 ++ runtime-light/stdlib/output/metrics.h | 161 ++++++++++++++++++ tests/python/lib/k2_server.py | 1 + 5 files changed, 194 insertions(+) create mode 100644 runtime-light/stdlib/output/metrics.h diff --git a/builtin-functions/kphp-light/stdlib/output-functions.txt b/builtin-functions/kphp-light/stdlib/output-functions.txt index 9dc5ef66ba..4e0894c3eb 100644 --- a/builtin-functions/kphp-light/stdlib/output-functions.txt +++ b/builtin-functions/kphp-light/stdlib/output-functions.txt @@ -19,3 +19,9 @@ function print ($v ::: string) ::: int; function echo ($v ::: string) ::: void; function dbg_echo ($v ::: string) ::: void; function var_dump ($v ::: any) ::: void; + +function write_metric_value ($metric_name ::: string, $tags ::: string[], $value ::: float, $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; +function write_metric_values_array ($metric_name ::: string, $tags ::: string[], $values ::: float[], $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; +function write_metric_count ($metric_name ::: string, $tags ::: string[], $count ::: float, $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; +function write_metric_increment ($metric_name ::: string, $tags ::: string[], $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; +function flush_metrics ($monitoring_system ::: int = 0) ::: void; diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 617dad5e3f..104ad9cb31 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -24,6 +24,8 @@ #include #define K2_API_HEADER_H +#include "runtime-common/core/allocator/script-allocator.h" +#include "runtime-common/core/std/containers.h" #include "runtime-light/k2-platform/k2-header.h" #undef K2_API_HEADER_H @@ -72,6 +74,10 @@ using StreamStatus = StreamStatus; using UpdateStatus = UpdateStatus; +using MonitoringSystem = MonitoringSystem; + +using MetricValueMask = MetricValueMask; + using TimePoint = TimePoint; using SystemTime = SystemTime; @@ -245,6 +251,14 @@ inline std::expected madvise(void* addr, size_t length, int32_t a return {}; } +inline void write_serialized_metric(kphp::stl::vector buf, k2::MonitoringSystem ms) noexcept { + k2_write_serialized_metric(buf.data(), buf.size(), ms); +} + +inline void flush_metrics(k2::MonitoringSystem ms) noexcept { + k2_flush_metrics(ms); +} + inline void please_shutdown(k2::descriptor descriptor) noexcept { k2_please_shutdown(descriptor); } diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index 25b8789f7f..e3d460f095 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -97,6 +97,10 @@ enum UpdateStatus { NewDescriptor = 2, }; +enum MonitoringSystem { StatsHouse }; + +enum MetricValueMask : uint32_t { VALUE_MASK = 0, VALUES_ARRAY_MASK = 1, COUNT_MASK = 2, INC_MASK = 3 }; + struct ImageInfo { // Base const char* image_name; @@ -382,6 +386,14 @@ void* k2_mmap(uint64_t* md, void* addr, size_t length, int32_t prot, int32_t fla * Semantically equivalent to libc's `madvise` function. */ int32_t k2_madvise(void* addr, size_t length, int32_t advise); +/** + * + * @param buf + * @param buf_len + * @param ms + */ +void k2_write_serialized_metric(uint8_t* buf, size_t buf_len, MonitoringSystem ms); +void k2_flush_metrics(enum MonitoringSystem ms); /** * Sets `StreamStatus.please_whutdown_write=true` for the component on the diff --git a/runtime-light/stdlib/output/metrics.h b/runtime-light/stdlib/output/metrics.h new file mode 100644 index 0000000000..9e9a71e1ab --- /dev/null +++ b/runtime-light/stdlib/output/metrics.h @@ -0,0 +1,161 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2026 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#pragma once + +#include +#include + +#include "runtime-common/core/allocator/script-allocator.h" +#include "runtime-common/core/runtime-core.h" +#include "runtime-common/core/std/containers.h" +#include "runtime-light/k2-platform/k2-api.h" + +struct MetricBuffer { +private: + using buf_vector = kphp::stl::vector; + using hasher_type = decltype([](const string& s) noexcept { return static_cast(s.hash()); }); + + string metric_name; + kphp::stl::unordered_map tags; + size_t msg_size{0}; + + MetricBuffer(std::string_view metric_name) noexcept + : metric_name{metric_name.data(), static_cast(metric_name.length())}, + tags{} { + this->msg_size += MetricBuffer::string_sizeof(metric_name); + } + + template + requires std::is_arithmetic_v + static void store_number(buf_vector& buf, const T& number) noexcept { + const auto* src = static_cast(static_cast(&number)); + buf.insert(buf.end(), src, src + sizeof(T)); + } + + static void store_string(buf_vector& buf, const std::string_view& string) noexcept { + MetricBuffer::store_number(buf, string.size()); + buf.insert(buf.end(), string.begin(), string.end()); + } + + void store_msg(buf_vector& buf) const noexcept { + MetricBuffer::store_number(buf, this->msg_size); + MetricBuffer::store_string(buf, std::string_view{this->metric_name.c_str(), this->metric_name.size()}); + for (const auto& [tag_name, tag_value] : this->tags) { + MetricBuffer::store_string(buf, std::string_view{tag_name.c_str(), tag_name.size()}); + MetricBuffer::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(); + } + +public: + static MetricBuffer builder(std::string_view metric_name) noexcept { + return MetricBuffer(metric_name); + } + + // ----------------------------------------------------------------- + static MetricBuffer from_php(const string& metric_name, const array& tags) noexcept { + auto builder = MetricBuffer::builder({metric_name.c_str(), metric_name.size()}); + for (const auto& it : tags) { + if (it.is_string_key()) { + const auto& tag_key = it.get_string_key(); + const auto& tag_val = it.get_value(); + builder.set_tag({tag_key.c_str(), tag_key.size()}, {tag_val.c_str(), tag_val.size()}); + } + } + return builder; + } + // ----------------------------------------------------------------- + + MetricBuffer& set_tag(std::string_view tag_name, std::string_view tag_value) noexcept { + this->tags[string{tag_name.data(), static_cast(tag_name.size())}] = + string{tag_value.data(), static_cast(tag_value.size())}; + this->msg_size += MetricBuffer::string_sizeof(tag_name) + MetricBuffer::string_sizeof(tag_value); + return *this; + } + + buf_vector build_value(double value, uint32_t timestamp) const noexcept { + buf_vector buf{}; + buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + this->msg_size); + + MetricBuffer::store_number(buf, timestamp); + MetricBuffer::store_number(buf, static_cast(k2::MetricValueMask::VALUE_MASK)); + MetricBuffer::store_number(buf, value); + this->store_msg(buf); + return buf; + } + + buf_vector build_values_array(const kphp::stl::vector& values, uint32_t timestamp) const noexcept { + buf_vector buf{}; + buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + this->msg_size); + + MetricBuffer::store_number(buf, timestamp); + MetricBuffer::store_number(buf, static_cast(k2::MetricValueMask::VALUES_ARRAY_MASK)); + MetricBuffer::store_number(buf, values.size()); + for (const auto& value : values) { + MetricBuffer::store_number(buf, value); + } + this->store_msg(buf); + return buf; + } + + buf_vector build_count(double count, uint32_t timestamp) const noexcept { + buf_vector buf{}; + buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + this->msg_size); + + MetricBuffer::store_number(buf, timestamp); + MetricBuffer::store_number(buf, static_cast(k2::MetricValueMask::COUNT_MASK)); + MetricBuffer::store_number(buf, count); + this->store_msg(buf); + return buf; + } + + buf_vector build_increment(uint32_t timestamp) const noexcept { + buf_vector buf{}; + buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + this->msg_size); + + MetricBuffer::store_number(buf, timestamp); + MetricBuffer::store_number(buf, static_cast(k2::MetricValueMask::INC_MASK)); + this->store_msg(buf); + return buf; + } +}; + +// ----------------------------------------------------------------- + +inline void f$write_metric_value(const string& metric_name, const array& tags, double value, int64_t monitoring_system = 0) noexcept { + auto builder = MetricBuffer::from_php(metric_name, tags); + auto timestamp{std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()}; + k2::write_serialized_metric(builder.build_value(value, static_cast(timestamp)), static_cast(monitoring_system)); +} + +inline void f$write_metric_values_array(const string& metric_name, const array& tags, const array& values, + int64_t monitoring_system = 0) noexcept { + auto builder = MetricBuffer::from_php(metric_name, tags); + auto timestamp{std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()}; + kphp::stl::vector vec{}; + for (const auto& it : values) { + vec.push_back(it.get_value()); + } + k2::write_serialized_metric(builder.build_values_array(vec, static_cast(timestamp)), static_cast(monitoring_system)); +} + +inline void f$write_metric_count(const string& metric_name, const array& tags, double count, int64_t monitoring_system = 0) noexcept { + auto builder = MetricBuffer::from_php(metric_name, tags); + auto timestamp{std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()}; + k2::write_serialized_metric(builder.build_count(count, static_cast(timestamp)), static_cast(monitoring_system)); +} + +inline void f$write_metric_increment(const string& metric_name, const array& tags, int64_t monitoring_system = 0) noexcept { + auto builder = MetricBuffer::from_php(metric_name, tags); + auto timestamp{std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()}; + k2::write_serialized_metric(builder.build_increment(static_cast(timestamp)), static_cast(monitoring_system)); +} + +inline void f$flush_metrics(int64_t monitoring_system = 0) noexcept { + k2::flush_metrics(static_cast(monitoring_system)); +} diff --git a/tests/python/lib/k2_server.py b/tests/python/lib/k2_server.py index f31fdfa254..ac5961bafc 100644 --- a/tests/python/lib/k2_server.py +++ b/tests/python/lib/k2_server.py @@ -71,6 +71,7 @@ def _process_json_log(self, log_record): log_record.pop("file", "") log_record.pop("line", "") log_record.pop("hostname", "") + log_record.pop("cluster", "") # convert raw string to python dict tags = log_record.get("tags") From 2b7be26d31f6592fe964c1e0d07e4ac7f6084bd6 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 19 Jun 2026 19:04:00 +0300 Subject: [PATCH 02/48] added metric builder + write_serialized_metric to k2-api --- .../kphp-light/stdlib/output-functions.txt | 1 - runtime-light/k2-platform/k2-api.h | 8 +- runtime-light/k2-platform/k2-header.h | 3 +- runtime-light/stdlib/output/metrics.h | 133 ++++++++++-------- 4 files changed, 76 insertions(+), 69 deletions(-) diff --git a/builtin-functions/kphp-light/stdlib/output-functions.txt b/builtin-functions/kphp-light/stdlib/output-functions.txt index 4e0894c3eb..30537540a5 100644 --- a/builtin-functions/kphp-light/stdlib/output-functions.txt +++ b/builtin-functions/kphp-light/stdlib/output-functions.txt @@ -24,4 +24,3 @@ function write_metric_value ($metric_name ::: string, $tags ::: string[], $value function write_metric_values_array ($metric_name ::: string, $tags ::: string[], $values ::: float[], $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; function write_metric_count ($metric_name ::: string, $tags ::: string[], $count ::: float, $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; function write_metric_increment ($metric_name ::: string, $tags ::: string[], $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; -function flush_metrics ($monitoring_system ::: int = 0) ::: void; diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 104ad9cb31..b353a69b76 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -251,12 +251,8 @@ inline std::expected madvise(void* addr, size_t length, int32_t a return {}; } -inline void write_serialized_metric(kphp::stl::vector buf, k2::MonitoringSystem ms) noexcept { - k2_write_serialized_metric(buf.data(), buf.size(), ms); -} - -inline void flush_metrics(k2::MonitoringSystem ms) noexcept { - k2_flush_metrics(ms); +inline void write_serialized_metric(kphp::stl::vector serialized_metric, k2::MonitoringSystem ms) noexcept { + k2_write_serialized_metric(serialized_metric.data(), serialized_metric.size(), ms); } inline void please_shutdown(k2::descriptor descriptor) noexcept { diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index e3d460f095..cd51c12bd7 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -386,14 +386,15 @@ void* k2_mmap(uint64_t* md, void* addr, size_t length, int32_t prot, int32_t fla * Semantically equivalent to libc's `madvise` function. */ int32_t k2_madvise(void* addr, size_t length, int32_t advise); + /** + * ... * * @param buf * @param buf_len * @param ms */ void k2_write_serialized_metric(uint8_t* buf, size_t buf_len, MonitoringSystem ms); -void k2_flush_metrics(enum MonitoringSystem ms); /** * Sets `StreamStatus.please_whutdown_write=true` for the component on the diff --git a/runtime-light/stdlib/output/metrics.h b/runtime-light/stdlib/output/metrics.h index 9e9a71e1ab..c81c3324f4 100644 --- a/runtime-light/stdlib/output/metrics.h +++ b/runtime-light/stdlib/output/metrics.h @@ -4,47 +4,48 @@ #pragma once +#include #include #include +#include "common/mixin/movable_only.h" #include "runtime-common/core/allocator/script-allocator.h" #include "runtime-common/core/runtime-core.h" #include "runtime-common/core/std/containers.h" #include "runtime-light/k2-platform/k2-api.h" -struct MetricBuffer { +struct MetricsBuffer final : vk::movable_only { private: - using buf_vector = kphp::stl::vector; + using bytes_vector = kphp::stl::vector; using hasher_type = decltype([](const string& s) noexcept { return static_cast(s.hash()); }); string metric_name; kphp::stl::unordered_map tags; size_t msg_size{0}; - MetricBuffer(std::string_view metric_name) noexcept - : metric_name{metric_name.data(), static_cast(metric_name.length())}, - tags{} { - this->msg_size += MetricBuffer::string_sizeof(metric_name); + MetricsBuffer(std::string_view metric_name) noexcept + : metric_name{metric_name.data(), static_cast(metric_name.length())} { + this->msg_size += MetricsBuffer::string_sizeof(metric_name); } template requires std::is_arithmetic_v - static void store_number(buf_vector& buf, const T& number) noexcept { + static void store_number(bytes_vector& buf, const T& number) noexcept { const auto* src = static_cast(static_cast(&number)); buf.insert(buf.end(), src, src + sizeof(T)); } - static void store_string(buf_vector& buf, const std::string_view& string) noexcept { - MetricBuffer::store_number(buf, string.size()); + static void store_string(bytes_vector& buf, const std::string_view& string) noexcept { + MetricsBuffer::store_number(buf, string.size()); buf.insert(buf.end(), string.begin(), string.end()); } - void store_msg(buf_vector& buf) const noexcept { - MetricBuffer::store_number(buf, this->msg_size); - MetricBuffer::store_string(buf, std::string_view{this->metric_name.c_str(), this->metric_name.size()}); + void store_msg(bytes_vector& buf) const noexcept { + MetricsBuffer::store_number(buf, this->msg_size); + MetricsBuffer::store_string(buf, std::string_view{this->metric_name.c_str(), this->metric_name.size()}); for (const auto& [tag_name, tag_value] : this->tags) { - MetricBuffer::store_string(buf, std::string_view{tag_name.c_str(), tag_name.size()}); - MetricBuffer::store_string(buf, std::string_view{tag_value.c_str(), tag_value.size()}); + MetricsBuffer::store_string(buf, std::string_view{tag_name.c_str(), tag_name.size()}); + MetricsBuffer::store_string(buf, std::string_view{tag_value.c_str(), tag_value.size()}); } } @@ -52,74 +53,90 @@ struct MetricBuffer { return sizeof(size_t) + string.size(); } + static uint32_t s_timestamp_now() noexcept { + return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + } + public: - static MetricBuffer builder(std::string_view metric_name) noexcept { - return MetricBuffer(metric_name); + static MetricsBuffer metric(std::string_view metric_name) noexcept { + return MetricsBuffer{metric_name}; } // ----------------------------------------------------------------- - static MetricBuffer from_php(const string& metric_name, const array& tags) noexcept { - auto builder = MetricBuffer::builder({metric_name.c_str(), metric_name.size()}); + static MetricsBuffer from_php(const string& metric_name, const array& tags) noexcept { + auto builder = MetricsBuffer::metric({metric_name.c_str(), metric_name.size()}); for (const auto& it : tags) { if (it.is_string_key()) { const auto& tag_key = it.get_string_key(); const auto& tag_val = it.get_value(); - builder.set_tag({tag_key.c_str(), tag_key.size()}, {tag_val.c_str(), tag_val.size()}); + builder.tag({tag_key.c_str(), tag_key.size()}, {tag_val.c_str(), tag_val.size()}); } } return builder; } // ----------------------------------------------------------------- - MetricBuffer& set_tag(std::string_view tag_name, std::string_view tag_value) noexcept { + MetricsBuffer& tag(std::string_view tag_name, std::string_view tag_value) noexcept { this->tags[string{tag_name.data(), static_cast(tag_name.size())}] = string{tag_value.data(), static_cast(tag_value.size())}; - this->msg_size += MetricBuffer::string_sizeof(tag_name) + MetricBuffer::string_sizeof(tag_value); + this->msg_size += MetricsBuffer::string_sizeof(tag_name) + MetricsBuffer::string_sizeof(tag_value); return *this; } - buf_vector build_value(double value, uint32_t timestamp) const noexcept { - buf_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + this->msg_size); + bytes_vector build_value(double value, std::optional timestamp = std::nullopt) const noexcept { + bytes_vector buf{}; + buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + + this->msg_size); // timestamp_u32 + value_mask_u32 + value_f64 + msg_size_usize + msg_len - MetricBuffer::store_number(buf, timestamp); - MetricBuffer::store_number(buf, static_cast(k2::MetricValueMask::VALUE_MASK)); - MetricBuffer::store_number(buf, value); + uint32_t s_timestamp{timestamp.value_or(MetricsBuffer::s_timestamp_now())}; + + MetricsBuffer::store_number(buf, s_timestamp); + MetricsBuffer::store_number(buf, static_cast(k2::MetricValueMask::VALUE_MASK)); + MetricsBuffer::store_number(buf, value); this->store_msg(buf); return buf; } - buf_vector build_values_array(const kphp::stl::vector& values, uint32_t timestamp) const noexcept { - buf_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + this->msg_size); + bytes_vector build_values_array(const kphp::stl::vector& values, + std::optional timestamp = std::nullopt) const noexcept { + bytes_vector buf{}; + buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + + this->msg_size); // timestamp_u32 + value_mask_u32 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len + + uint32_t s_timestamp{timestamp.value_or(MetricsBuffer::s_timestamp_now())}; - MetricBuffer::store_number(buf, timestamp); - MetricBuffer::store_number(buf, static_cast(k2::MetricValueMask::VALUES_ARRAY_MASK)); - MetricBuffer::store_number(buf, values.size()); + MetricsBuffer::store_number(buf, s_timestamp); + MetricsBuffer::store_number(buf, static_cast(k2::MetricValueMask::VALUES_ARRAY_MASK)); + MetricsBuffer::store_number(buf, values.size()); for (const auto& value : values) { - MetricBuffer::store_number(buf, value); + MetricsBuffer::store_number(buf, value); } this->store_msg(buf); return buf; } - buf_vector build_count(double count, uint32_t timestamp) const noexcept { - buf_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + this->msg_size); + bytes_vector build_count(double count, std::optional timestamp = std::nullopt) const noexcept { + bytes_vector buf{}; + buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + + this->msg_size); // timestamp_u32 + value_mask_u32 + count_f64 + msg_size_usize + msg_len - MetricBuffer::store_number(buf, timestamp); - MetricBuffer::store_number(buf, static_cast(k2::MetricValueMask::COUNT_MASK)); - MetricBuffer::store_number(buf, count); + uint32_t s_timestamp{timestamp.value_or(MetricsBuffer::s_timestamp_now())}; + + MetricsBuffer::store_number(buf, s_timestamp); + MetricsBuffer::store_number(buf, static_cast(k2::MetricValueMask::COUNT_MASK)); + MetricsBuffer::store_number(buf, count); this->store_msg(buf); return buf; } - buf_vector build_increment(uint32_t timestamp) const noexcept { - buf_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + this->msg_size); + bytes_vector build_increment(std::optional timestamp = std::nullopt) const noexcept { + bytes_vector buf{}; + buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_mask_u32 + msg_size_usize + msg_len + + uint32_t s_timestamp{timestamp.value_or(MetricsBuffer::s_timestamp_now())}; - MetricBuffer::store_number(buf, timestamp); - MetricBuffer::store_number(buf, static_cast(k2::MetricValueMask::INC_MASK)); + MetricsBuffer::store_number(buf, s_timestamp); + MetricsBuffer::store_number(buf, static_cast(k2::MetricValueMask::INC_MASK)); this->store_msg(buf); return buf; } @@ -127,16 +144,15 @@ struct MetricBuffer { // ----------------------------------------------------------------- -inline void f$write_metric_value(const string& metric_name, const array& tags, double value, int64_t monitoring_system = 0) noexcept { - auto builder = MetricBuffer::from_php(metric_name, tags); - auto timestamp{std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()}; +inline void f$write_metric_value(const string& metric_name, const array& tags, double value, uint32_t timestamp = 0, + int64_t monitoring_system = 0) noexcept { + auto builder = MetricsBuffer::from_php(metric_name, tags); k2::write_serialized_metric(builder.build_value(value, static_cast(timestamp)), static_cast(monitoring_system)); } -inline void f$write_metric_values_array(const string& metric_name, const array& tags, const array& values, +inline void f$write_metric_values_array(const string& metric_name, const array& tags, const array& values, uint32_t timestamp = 0, int64_t monitoring_system = 0) noexcept { - auto builder = MetricBuffer::from_php(metric_name, tags); - auto timestamp{std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()}; + auto builder = MetricsBuffer::from_php(metric_name, tags); kphp::stl::vector vec{}; for (const auto& it : values) { vec.push_back(it.get_value()); @@ -144,18 +160,13 @@ inline void f$write_metric_values_array(const string& metric_name, const array(timestamp)), static_cast(monitoring_system)); } -inline void f$write_metric_count(const string& metric_name, const array& tags, double count, int64_t monitoring_system = 0) noexcept { - auto builder = MetricBuffer::from_php(metric_name, tags); - auto timestamp{std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()}; +inline void f$write_metric_count(const string& metric_name, const array& tags, double count, uint32_t timestamp = 0, + int64_t monitoring_system = 0) noexcept { + auto builder = MetricsBuffer::from_php(metric_name, tags); k2::write_serialized_metric(builder.build_count(count, static_cast(timestamp)), static_cast(monitoring_system)); } -inline void f$write_metric_increment(const string& metric_name, const array& tags, int64_t monitoring_system = 0) noexcept { - auto builder = MetricBuffer::from_php(metric_name, tags); - auto timestamp{std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()}; +inline void f$write_metric_increment(const string& metric_name, const array& tags, uint32_t timestamp = 0, int64_t monitoring_system = 0) noexcept { + auto builder = MetricsBuffer::from_php(metric_name, tags); k2::write_serialized_metric(builder.build_increment(static_cast(timestamp)), static_cast(monitoring_system)); } - -inline void f$flush_metrics(int64_t monitoring_system = 0) noexcept { - k2::flush_metrics(static_cast(monitoring_system)); -} From 7bb602d40e403b24be19b63dc1f7eaa97b32ee20 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 19 Jun 2026 19:12:15 +0300 Subject: [PATCH 03/48] v1.0 --- .../kphp-light/stdlib/output-functions.txt | 5 --- runtime-light/stdlib/output/metrics.h | 45 +------------------ tests/python/lib/k2_server.py | 1 - 3 files changed, 1 insertion(+), 50 deletions(-) diff --git a/builtin-functions/kphp-light/stdlib/output-functions.txt b/builtin-functions/kphp-light/stdlib/output-functions.txt index 30537540a5..9dc5ef66ba 100644 --- a/builtin-functions/kphp-light/stdlib/output-functions.txt +++ b/builtin-functions/kphp-light/stdlib/output-functions.txt @@ -19,8 +19,3 @@ function print ($v ::: string) ::: int; function echo ($v ::: string) ::: void; function dbg_echo ($v ::: string) ::: void; function var_dump ($v ::: any) ::: void; - -function write_metric_value ($metric_name ::: string, $tags ::: string[], $value ::: float, $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; -function write_metric_values_array ($metric_name ::: string, $tags ::: string[], $values ::: float[], $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; -function write_metric_count ($metric_name ::: string, $tags ::: string[], $count ::: float, $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; -function write_metric_increment ($metric_name ::: string, $tags ::: string[], $timestamp ::: int = 0, $monitoring_system ::: int = 0) ::: void; diff --git a/runtime-light/stdlib/output/metrics.h b/runtime-light/stdlib/output/metrics.h index c81c3324f4..93254b0964 100644 --- a/runtime-light/stdlib/output/metrics.h +++ b/runtime-light/stdlib/output/metrics.h @@ -23,7 +23,7 @@ struct MetricsBuffer final : vk::movable_only { kphp::stl::unordered_map tags; size_t msg_size{0}; - MetricsBuffer(std::string_view metric_name) noexcept + explicit MetricsBuffer(std::string_view metric_name) noexcept : metric_name{metric_name.data(), static_cast(metric_name.length())} { this->msg_size += MetricsBuffer::string_sizeof(metric_name); } @@ -62,20 +62,6 @@ struct MetricsBuffer final : vk::movable_only { return MetricsBuffer{metric_name}; } - // ----------------------------------------------------------------- - static MetricsBuffer from_php(const string& metric_name, const array& tags) noexcept { - auto builder = MetricsBuffer::metric({metric_name.c_str(), metric_name.size()}); - for (const auto& it : tags) { - if (it.is_string_key()) { - const auto& tag_key = it.get_string_key(); - const auto& tag_val = it.get_value(); - builder.tag({tag_key.c_str(), tag_key.size()}, {tag_val.c_str(), tag_val.size()}); - } - } - return builder; - } - // ----------------------------------------------------------------- - MetricsBuffer& tag(std::string_view tag_name, std::string_view tag_value) noexcept { this->tags[string{tag_name.data(), static_cast(tag_name.size())}] = string{tag_value.data(), static_cast(tag_value.size())}; @@ -141,32 +127,3 @@ struct MetricsBuffer final : vk::movable_only { return buf; } }; - -// ----------------------------------------------------------------- - -inline void f$write_metric_value(const string& metric_name, const array& tags, double value, uint32_t timestamp = 0, - int64_t monitoring_system = 0) noexcept { - auto builder = MetricsBuffer::from_php(metric_name, tags); - k2::write_serialized_metric(builder.build_value(value, static_cast(timestamp)), static_cast(monitoring_system)); -} - -inline void f$write_metric_values_array(const string& metric_name, const array& tags, const array& values, uint32_t timestamp = 0, - int64_t monitoring_system = 0) noexcept { - auto builder = MetricsBuffer::from_php(metric_name, tags); - kphp::stl::vector vec{}; - for (const auto& it : values) { - vec.push_back(it.get_value()); - } - k2::write_serialized_metric(builder.build_values_array(vec, static_cast(timestamp)), static_cast(monitoring_system)); -} - -inline void f$write_metric_count(const string& metric_name, const array& tags, double count, uint32_t timestamp = 0, - int64_t monitoring_system = 0) noexcept { - auto builder = MetricsBuffer::from_php(metric_name, tags); - k2::write_serialized_metric(builder.build_count(count, static_cast(timestamp)), static_cast(monitoring_system)); -} - -inline void f$write_metric_increment(const string& metric_name, const array& tags, uint32_t timestamp = 0, int64_t monitoring_system = 0) noexcept { - auto builder = MetricsBuffer::from_php(metric_name, tags); - k2::write_serialized_metric(builder.build_increment(static_cast(timestamp)), static_cast(monitoring_system)); -} diff --git a/tests/python/lib/k2_server.py b/tests/python/lib/k2_server.py index ac5961bafc..f31fdfa254 100644 --- a/tests/python/lib/k2_server.py +++ b/tests/python/lib/k2_server.py @@ -71,7 +71,6 @@ def _process_json_log(self, log_record): log_record.pop("file", "") log_record.pop("line", "") log_record.pop("hostname", "") - log_record.pop("cluster", "") # convert raw string to python dict tags = log_record.get("tags") From f6af9d2bf689ff638c720b4b653df9deed517c64 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Sun, 21 Jun 2026 13:58:43 +0300 Subject: [PATCH 04/48] v1.1 --- runtime-light/k2-platform/k2-api.h | 4 ++-- runtime-light/k2-platform/k2-header.h | 22 ++++++++++++++----- .../stdlib/{output => diagnostics}/metrics.h | 11 ++++------ 3 files changed, 23 insertions(+), 14 deletions(-) rename runtime-light/stdlib/{output => diagnostics}/metrics.h (90%) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index b353a69b76..0b8b8c931a 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -251,8 +251,8 @@ inline std::expected madvise(void* addr, size_t length, int32_t a return {}; } -inline void write_serialized_metric(kphp::stl::vector serialized_metric, k2::MonitoringSystem ms) noexcept { - k2_write_serialized_metric(serialized_metric.data(), serialized_metric.size(), ms); +inline void write_metric(const kphp::stl::vector& serialized_metric, k2::MonitoringSystem ms) noexcept { + k2_write_metric(serialized_metric.data(), serialized_metric.size(), ms); } inline void please_shutdown(k2::descriptor descriptor) noexcept { diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index cd51c12bd7..393921deaa 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -99,6 +99,16 @@ enum UpdateStatus { enum MonitoringSystem { StatsHouse }; +/* + * Serialized metric format: + * ... + * + * value_format: + * - single float value + * ... - array of float values + * - count value + * - counter increment (no payload) + */ enum MetricValueMask : uint32_t { VALUE_MASK = 0, VALUES_ARRAY_MASK = 1, COUNT_MASK = 2, INC_MASK = 3 }; struct ImageInfo { @@ -388,13 +398,15 @@ 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 - * @param buf_len - * @param ms + * @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_serialized_metric(uint8_t* buf, size_t buf_len, MonitoringSystem ms); +void k2_write_metric(const uint8_t* buf, size_t buf_len, enum MonitoringSystem ms); /** * Sets `StreamStatus.please_whutdown_write=true` for the component on the diff --git a/runtime-light/stdlib/output/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h similarity index 90% rename from runtime-light/stdlib/output/metrics.h rename to runtime-light/stdlib/diagnostics/metrics.h index 93254b0964..dc40dcef68 100644 --- a/runtime-light/stdlib/output/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -10,21 +10,19 @@ #include "common/mixin/movable_only.h" #include "runtime-common/core/allocator/script-allocator.h" -#include "runtime-common/core/runtime-core.h" #include "runtime-common/core/std/containers.h" #include "runtime-light/k2-platform/k2-api.h" struct MetricsBuffer final : vk::movable_only { private: using bytes_vector = kphp::stl::vector; - using hasher_type = decltype([](const string& s) noexcept { return static_cast(s.hash()); }); - string metric_name; - kphp::stl::unordered_map tags; + std::string metric_name; + kphp::stl::unordered_map tags; size_t msg_size{0}; explicit MetricsBuffer(std::string_view metric_name) noexcept - : metric_name{metric_name.data(), static_cast(metric_name.length())} { + : metric_name{metric_name} { this->msg_size += MetricsBuffer::string_sizeof(metric_name); } @@ -63,8 +61,7 @@ struct MetricsBuffer final : vk::movable_only { } MetricsBuffer& tag(std::string_view tag_name, std::string_view tag_value) noexcept { - this->tags[string{tag_name.data(), static_cast(tag_name.size())}] = - string{tag_value.data(), static_cast(tag_value.size())}; + this->tags[std::string{tag_name}] = std::string{tag_value}; this->msg_size += MetricsBuffer::string_sizeof(tag_name) + MetricsBuffer::string_sizeof(tag_value); return *this; } From 0608cf2d2ed6471c9ce762ff064b7c1e6324aa03 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Sun, 21 Jun 2026 14:55:45 +0300 Subject: [PATCH 05/48] rename --- runtime-light/stdlib/diagnostics/metrics.h | 56 +++++++++++----------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index dc40dcef68..2b3cc402d5 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -13,7 +13,7 @@ #include "runtime-common/core/std/containers.h" #include "runtime-light/k2-platform/k2-api.h" -struct MetricsBuffer final : vk::movable_only { +struct MetricBuilder final : vk::movable_only { private: using bytes_vector = kphp::stl::vector; @@ -21,9 +21,9 @@ struct MetricsBuffer final : vk::movable_only { kphp::stl::unordered_map tags; size_t msg_size{0}; - explicit MetricsBuffer(std::string_view metric_name) noexcept + explicit MetricBuilder(std::string_view metric_name) noexcept : metric_name{metric_name} { - this->msg_size += MetricsBuffer::string_sizeof(metric_name); + this->msg_size += MetricBuilder::string_sizeof(metric_name); } template @@ -34,16 +34,16 @@ struct MetricsBuffer final : vk::movable_only { } static void store_string(bytes_vector& buf, const std::string_view& string) noexcept { - MetricsBuffer::store_number(buf, string.size()); + MetricBuilder::store_number(buf, string.size()); buf.insert(buf.end(), string.begin(), string.end()); } void store_msg(bytes_vector& buf) const noexcept { - MetricsBuffer::store_number(buf, this->msg_size); - MetricsBuffer::store_string(buf, std::string_view{this->metric_name.c_str(), this->metric_name.size()}); + 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) { - MetricsBuffer::store_string(buf, std::string_view{tag_name.c_str(), tag_name.size()}); - MetricsBuffer::store_string(buf, std::string_view{tag_value.c_str(), tag_value.size()}); + 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()}); } } @@ -56,13 +56,13 @@ struct MetricsBuffer final : vk::movable_only { } public: - static MetricsBuffer metric(std::string_view metric_name) noexcept { - return MetricsBuffer{metric_name}; + static MetricBuilder metric(std::string_view metric_name) noexcept { + return MetricBuilder{metric_name}; } - MetricsBuffer& tag(std::string_view tag_name, std::string_view tag_value) noexcept { + 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 += MetricsBuffer::string_sizeof(tag_name) + MetricsBuffer::string_sizeof(tag_value); + this->msg_size += MetricBuilder::string_sizeof(tag_name) + MetricBuilder::string_sizeof(tag_value); return *this; } @@ -71,11 +71,11 @@ struct MetricsBuffer final : vk::movable_only { buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_mask_u32 + value_f64 + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(MetricsBuffer::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; - MetricsBuffer::store_number(buf, s_timestamp); - MetricsBuffer::store_number(buf, static_cast(k2::MetricValueMask::VALUE_MASK)); - MetricsBuffer::store_number(buf, value); + MetricBuilder::store_number(buf, s_timestamp); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueMask::VALUE_MASK)); + MetricBuilder::store_number(buf, value); this->store_msg(buf); return buf; } @@ -86,13 +86,13 @@ struct MetricsBuffer final : vk::movable_only { buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_mask_u32 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(MetricsBuffer::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; - MetricsBuffer::store_number(buf, s_timestamp); - MetricsBuffer::store_number(buf, static_cast(k2::MetricValueMask::VALUES_ARRAY_MASK)); - MetricsBuffer::store_number(buf, values.size()); + MetricBuilder::store_number(buf, s_timestamp); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueMask::VALUES_ARRAY_MASK)); + MetricBuilder::store_number(buf, values.size()); for (const auto& value : values) { - MetricsBuffer::store_number(buf, value); + MetricBuilder::store_number(buf, value); } this->store_msg(buf); return buf; @@ -103,11 +103,11 @@ struct MetricsBuffer final : vk::movable_only { buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_mask_u32 + count_f64 + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(MetricsBuffer::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; - MetricsBuffer::store_number(buf, s_timestamp); - MetricsBuffer::store_number(buf, static_cast(k2::MetricValueMask::COUNT_MASK)); - MetricsBuffer::store_number(buf, count); + MetricBuilder::store_number(buf, s_timestamp); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueMask::COUNT_MASK)); + MetricBuilder::store_number(buf, count); this->store_msg(buf); return buf; } @@ -116,10 +116,10 @@ struct MetricsBuffer final : vk::movable_only { bytes_vector buf{}; buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_mask_u32 + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(MetricsBuffer::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; - MetricsBuffer::store_number(buf, s_timestamp); - MetricsBuffer::store_number(buf, static_cast(k2::MetricValueMask::INC_MASK)); + MetricBuilder::store_number(buf, s_timestamp); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueMask::INC_MASK)); this->store_msg(buf); return buf; } From 12b21ac2294e0edd94a3185e5b60483101945ad2 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Sun, 21 Jun 2026 20:13:22 +0300 Subject: [PATCH 06/48] mask size 32bits to 8bits --- runtime-light/k2-platform/k2-header.h | 2 +- runtime-light/stdlib/diagnostics/metrics.h | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index 393921deaa..f4408693ab 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -109,7 +109,7 @@ enum MonitoringSystem { StatsHouse }; * - count value * - counter increment (no payload) */ -enum MetricValueMask : uint32_t { VALUE_MASK = 0, VALUES_ARRAY_MASK = 1, COUNT_MASK = 2, INC_MASK = 3 }; +enum MetricValueMask : uint8_t { VALUE_MASK = 0, VALUES_ARRAY_MASK = 1, COUNT_MASK = 2, INC_MASK = 3 }; struct ImageInfo { // Base diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 2b3cc402d5..36424b9a86 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -68,13 +68,13 @@ struct MetricBuilder final : vk::movable_only { bytes_vector build_value(double value, std::optional timestamp = std::nullopt) const noexcept { bytes_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + - this->msg_size); // timestamp_u32 + value_mask_u32 + value_f64 + msg_size_usize + msg_len + 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(k2::MetricValueMask::VALUE_MASK)); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueMask::VALUE_MASK)); MetricBuilder::store_number(buf, value); this->store_msg(buf); return buf; @@ -83,13 +83,13 @@ struct MetricBuilder final : vk::movable_only { bytes_vector build_values_array(const kphp::stl::vector& values, std::optional timestamp = std::nullopt) const noexcept { bytes_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + - this->msg_size); // timestamp_u32 + value_mask_u32 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len + 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(k2::MetricValueMask::VALUES_ARRAY_MASK)); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueMask::VALUES_ARRAY_MASK)); MetricBuilder::store_number(buf, values.size()); for (const auto& value : values) { MetricBuilder::store_number(buf, value); @@ -100,13 +100,13 @@ struct MetricBuilder final : vk::movable_only { bytes_vector build_count(double count, std::optional timestamp = std::nullopt) const noexcept { bytes_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double) + sizeof(size_t) + - this->msg_size); // timestamp_u32 + value_mask_u32 + count_f64 + msg_size_usize + msg_len + 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(k2::MetricValueMask::COUNT_MASK)); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueMask::COUNT_MASK)); MetricBuilder::store_number(buf, count); this->store_msg(buf); return buf; @@ -114,12 +114,12 @@ struct MetricBuilder final : vk::movable_only { bytes_vector build_increment(std::optional timestamp = std::nullopt) const noexcept { bytes_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_mask_u32 + msg_size_usize + msg_len + 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(k2::MetricValueMask::INC_MASK)); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueMask::INC_MASK)); this->store_msg(buf); return buf; } From 5bb69d9a352e291287c3445237855406f7ab688f Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 22 Jun 2026 15:35:07 +0300 Subject: [PATCH 07/48] fixes --- runtime-light/k2-platform/k2-api.h | 11 +- runtime-light/k2-platform/k2-header.h | 14 +-- runtime-light/stdlib/diagnostics/metrics.h | 111 +++++++++++++++++---- 3 files changed, 107 insertions(+), 29 deletions(-) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 0b8b8c931a..b7f046ed69 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -24,8 +24,6 @@ #include #define K2_API_HEADER_H -#include "runtime-common/core/allocator/script-allocator.h" -#include "runtime-common/core/std/containers.h" #include "runtime-light/k2-platform/k2-header.h" #undef K2_API_HEADER_H @@ -76,7 +74,7 @@ using UpdateStatus = UpdateStatus; using MonitoringSystem = MonitoringSystem; -using MetricValueMask = MetricValueMask; +using MetricValueKind = MetricValueKind; using TimePoint = TimePoint; @@ -251,8 +249,11 @@ inline std::expected madvise(void* addr, size_t length, int32_t a return {}; } -inline void write_metric(const kphp::stl::vector& serialized_metric, k2::MonitoringSystem ms) noexcept { - k2_write_metric(serialized_metric.data(), serialized_metric.size(), ms); +inline std::expected write_metric(const std::span serialized_metric, k2::MonitoringSystem ms) noexcept { + if (auto error_code{k2_write_metric(serialized_metric.data(), serialized_metric.size(), ms)}; error_code != k2::errno_ok) { + return std::unexpected{error_code}; + } + return {}; } inline void please_shutdown(k2::descriptor descriptor) noexcept { diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index f4408693ab..da1592062c 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -104,12 +104,14 @@ enum MonitoringSystem { StatsHouse }; * ... * * value_format: - * - single float value - * ... - array of float values - * - count value - * - counter increment (no payload) + * - single float value + * ... - array of float values + * - count value + * - counter increment + * + * msg_size: sizeof(metric_name_len) + sizeof(metric_name) + sizeof(tag1_name_len) + sizeof(tag1_name) + sizeof(tag1_value_len) + sizeof(tag1_value) + ... */ -enum MetricValueMask : uint8_t { VALUE_MASK = 0, VALUES_ARRAY_MASK = 1, COUNT_MASK = 2, INC_MASK = 3 }; +enum MetricValueKind : uint8_t { VALUE, VALUES_ARRAY, COUNT, INC }; struct ImageInfo { // Base @@ -406,7 +408,7 @@ int32_t k2_madvise(void* addr, size_t length, int32_t advise); * @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); +int32_t k2_write_metric(const void* buf, size_t buf_len, enum MonitoringSystem ms); /** * Sets `StreamStatus.please_whutdown_write=true` for the component on the diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 36424b9a86..fe4f83b790 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -7,18 +7,27 @@ #include #include #include +#include +#include +#include +#include +#include "common/containers/final_action.h" #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" +namespace kphp::diagnostics { struct MetricBuilder final : vk::movable_only { +public: + using bytes_vector = kphp::stl::vector; + private: - using bytes_vector = kphp::stl::vector; + using string = kphp::stl::string; - std::string metric_name; - kphp::stl::unordered_map tags; + string metric_name; + kphp::stl::vector, kphp::memory::script_allocator> tags; size_t msg_size{0}; explicit MetricBuilder(std::string_view metric_name) noexcept @@ -29,24 +38,37 @@ struct MetricBuilder final : vk::movable_only { template requires std::is_arithmetic_v static void store_number(bytes_vector& buf, const T& number) noexcept { - const auto* src = static_cast(static_cast(&number)); + const auto* src{static_cast(static_cast(std::addressof(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()); + std::transform(string.begin(), string.end(), std::back_inserter(buf), [](char c) { return std::byte(c); }); + } + + static void store_tag(bytes_vector& buf, std::pair tag) noexcept { + MetricBuilder::store_string(buf, tag.first); + MetricBuilder::store_string(buf, tag.second); } 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()}); + MetricBuilder::store_tag(buf, {std::string_view{tag_name.c_str(), tag_name.size()}, std::string_view{tag_value.c_str(), tag_value.size()}}); } } + auto send_helper(const std::initializer_list>& tags) noexcept { + size_t tags_size{}; + for (const auto& [tag_name, tag_value] : tags) { + tags_size += MetricBuilder::string_sizeof(tag_name) + MetricBuilder::string_sizeof(tag_value); + } + this->msg_size += tags_size; + return vk::final_action{[tags_size, this]() { this->msg_size -= tags_size; }}; + } + static size_t string_sizeof(const std::string_view& string) noexcept { return sizeof(size_t) + string.size(); } @@ -56,12 +78,16 @@ struct MetricBuilder final : vk::movable_only { } public: + static std::expected send(bytes_vector& buf, k2::MonitoringSystem ms) noexcept { + return k2::write_metric(std::span{buf.data(), buf.size()}, ms); + } + 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->tags.emplace_back(tag_name, tag_value); this->msg_size += MetricBuilder::string_sizeof(tag_name) + MetricBuilder::string_sizeof(tag_value); return *this; } @@ -69,27 +95,26 @@ struct MetricBuilder final : vk::movable_only { bytes_vector build_value(double value, std::optional 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 + this->msg_size); // timestamp_u32 + value_kind_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(k2::MetricValueMask::VALUE_MASK)); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueKind::VALUE)); MetricBuilder::store_number(buf, value); this->store_msg(buf); return buf; } - bytes_vector build_values_array(const kphp::stl::vector& values, - std::optional timestamp = std::nullopt) const noexcept { + bytes_vector build_values_array(std::initializer_list values, std::optional 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 + this->msg_size); // timestamp_u32 + value_kind_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(k2::MetricValueMask::VALUES_ARRAY_MASK)); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueKind::VALUES_ARRAY)); MetricBuilder::store_number(buf, values.size()); for (const auto& value : values) { MetricBuilder::store_number(buf, value); @@ -101,12 +126,12 @@ struct MetricBuilder final : vk::movable_only { bytes_vector build_count(double count, std::optional 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 + this->msg_size); // timestamp_u32 + value_kind_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(k2::MetricValueMask::COUNT_MASK)); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueKind::COUNT)); MetricBuilder::store_number(buf, count); this->store_msg(buf); return buf; @@ -114,13 +139,63 @@ struct MetricBuilder final : vk::movable_only { bytes_vector build_increment(std::optional 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 + buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_kind_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(k2::MetricValueMask::INC_MASK)); + MetricBuilder::store_number(buf, static_cast(k2::MetricValueKind::INC)); this->store_msg(buf); return buf; } + + std::expected send_value(double value, k2::MonitoringSystem ms, std::initializer_list> tags = {}, + std::optional timestamp = std::nullopt) noexcept { + auto final_action{send_helper(tags)}; + + auto buf{this->build_value(value, timestamp)}; + for (const auto& tag : tags) { + MetricBuilder::store_tag(buf, tag); + } + + return MetricBuilder::send(buf, ms); + } + + std::expected send_values_array(std::initializer_list values, k2::MonitoringSystem ms, + std::initializer_list> tags = {}, + std::optional timestamp = std::nullopt) noexcept { + auto final_action{send_helper(tags)}; + + auto buf{this->build_values_array(values, timestamp)}; + for (const auto& tag : tags) { + MetricBuilder::store_tag(buf, tag); + } + + return MetricBuilder::send(buf, ms); + } + + std::expected send_count(double count, k2::MonitoringSystem ms, std::initializer_list> tags = {}, + std::optional timestamp = std::nullopt) noexcept { + auto final_action{send_helper(tags)}; + + auto buf{this->build_count(count, timestamp)}; + for (const auto& tag : tags) { + MetricBuilder::store_tag(buf, tag); + } + + return MetricBuilder::send(buf, ms); + } + + std::expected send_increment(k2::MonitoringSystem ms, std::initializer_list> tags = {}, + std::optional timestamp = std::nullopt) noexcept { + auto final_action{send_helper(tags)}; + + auto buf{this->build_increment(timestamp)}; + for (const auto& tag : tags) { + MetricBuilder::store_tag(buf, tag); + } + + return MetricBuilder::send(buf, ms); + } }; +} // namespace kphp::diagnostics From f8f635f9b381301d585aca96cec89014d96b1fc1 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 22 Jun 2026 16:59:20 +0300 Subject: [PATCH 08/48] fixes --- runtime-light/stdlib/diagnostics/metrics.h | 86 +++++++++++----------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index fe4f83b790..3f5e637248 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -19,20 +19,20 @@ #include "runtime-light/k2-platform/k2-api.h" namespace kphp::diagnostics { -struct MetricBuilder final : vk::movable_only { +struct metric_builder final : vk::movable_only { public: using bytes_vector = kphp::stl::vector; private: - using string = kphp::stl::string; - - string metric_name; - kphp::stl::vector, kphp::memory::script_allocator> tags; + kphp::stl::string metric_name; + kphp::stl::vector, kphp::stl::string>, + kphp::memory::script_allocator> + tags; size_t msg_size{0}; - explicit MetricBuilder(std::string_view metric_name) noexcept + explicit metric_builder(std::string_view metric_name) noexcept : metric_name{metric_name} { - this->msg_size += MetricBuilder::string_sizeof(metric_name); + this->msg_size += metric_builder::string_sizeof(metric_name); } template @@ -43,30 +43,30 @@ struct MetricBuilder final : vk::movable_only { } static void store_string(bytes_vector& buf, const std::string_view& string) noexcept { - MetricBuilder::store_number(buf, string.size()); + metric_builder::store_number(buf, string.size()); std::transform(string.begin(), string.end(), std::back_inserter(buf), [](char c) { return std::byte(c); }); } static void store_tag(bytes_vector& buf, std::pair tag) noexcept { - MetricBuilder::store_string(buf, tag.first); - MetricBuilder::store_string(buf, tag.second); + metric_builder::store_string(buf, tag.first); + metric_builder::store_string(buf, tag.second); } 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()}); + metric_builder::store_number(buf, this->msg_size); + metric_builder::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_tag(buf, {std::string_view{tag_name.c_str(), tag_name.size()}, std::string_view{tag_value.c_str(), tag_value.size()}}); + metric_builder::store_tag(buf, {std::string_view{tag_name.c_str(), tag_name.size()}, std::string_view{tag_value.c_str(), tag_value.size()}}); } } auto send_helper(const std::initializer_list>& tags) noexcept { size_t tags_size{}; for (const auto& [tag_name, tag_value] : tags) { - tags_size += MetricBuilder::string_sizeof(tag_name) + MetricBuilder::string_sizeof(tag_value); + tags_size += metric_builder::string_sizeof(tag_name) + metric_builder::string_sizeof(tag_value); } this->msg_size += tags_size; - return vk::final_action{[tags_size, this]() { this->msg_size -= tags_size; }}; + return vk::final_action{[tags_size, this]() noexcept { this->msg_size -= tags_size; }}; } static size_t string_sizeof(const std::string_view& string) noexcept { @@ -82,13 +82,13 @@ struct MetricBuilder final : vk::movable_only { return k2::write_metric(std::span{buf.data(), buf.size()}, ms); } - static MetricBuilder metric(std::string_view metric_name) noexcept { - return MetricBuilder{metric_name}; + static metric_builder metric(std::string_view metric_name) noexcept { + return metric_builder{metric_name}; } - MetricBuilder& tag(std::string_view tag_name, std::string_view tag_value) noexcept { + metric_builder& tag(std::string_view tag_name, std::string_view tag_value) noexcept { this->tags.emplace_back(tag_name, tag_value); - this->msg_size += MetricBuilder::string_sizeof(tag_name) + MetricBuilder::string_sizeof(tag_value); + this->msg_size += metric_builder::string_sizeof(tag_name) + metric_builder::string_sizeof(tag_value); return *this; } @@ -97,11 +97,11 @@ struct MetricBuilder final : vk::movable_only { buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_kind_u8 + value_f64 + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(metric_builder::s_timestamp_now())}; - MetricBuilder::store_number(buf, s_timestamp); - MetricBuilder::store_number(buf, static_cast(k2::MetricValueKind::VALUE)); - MetricBuilder::store_number(buf, value); + metric_builder::store_number(buf, s_timestamp); + metric_builder::store_number(buf, static_cast(k2::MetricValueKind::VALUE)); + metric_builder::store_number(buf, value); this->store_msg(buf); return buf; } @@ -111,13 +111,13 @@ struct MetricBuilder final : vk::movable_only { buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(metric_builder::s_timestamp_now())}; - MetricBuilder::store_number(buf, s_timestamp); - MetricBuilder::store_number(buf, static_cast(k2::MetricValueKind::VALUES_ARRAY)); - MetricBuilder::store_number(buf, values.size()); + metric_builder::store_number(buf, s_timestamp); + metric_builder::store_number(buf, static_cast(k2::MetricValueKind::VALUES_ARRAY)); + metric_builder::store_number(buf, values.size()); for (const auto& value : values) { - MetricBuilder::store_number(buf, value); + metric_builder::store_number(buf, value); } this->store_msg(buf); return buf; @@ -128,11 +128,11 @@ struct MetricBuilder final : vk::movable_only { buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_kind_u8 + count_f64 + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(metric_builder::s_timestamp_now())}; - MetricBuilder::store_number(buf, s_timestamp); - MetricBuilder::store_number(buf, static_cast(k2::MetricValueKind::COUNT)); - MetricBuilder::store_number(buf, count); + metric_builder::store_number(buf, s_timestamp); + metric_builder::store_number(buf, static_cast(k2::MetricValueKind::COUNT)); + metric_builder::store_number(buf, count); this->store_msg(buf); return buf; } @@ -141,10 +141,10 @@ struct MetricBuilder final : vk::movable_only { bytes_vector buf{}; buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_kind_u8 + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(metric_builder::s_timestamp_now())}; - MetricBuilder::store_number(buf, s_timestamp); - MetricBuilder::store_number(buf, static_cast(k2::MetricValueKind::INC)); + metric_builder::store_number(buf, s_timestamp); + metric_builder::store_number(buf, static_cast(k2::MetricValueKind::INC)); this->store_msg(buf); return buf; } @@ -155,10 +155,10 @@ struct MetricBuilder final : vk::movable_only { auto buf{this->build_value(value, timestamp)}; for (const auto& tag : tags) { - MetricBuilder::store_tag(buf, tag); + metric_builder::store_tag(buf, tag); } - return MetricBuilder::send(buf, ms); + return metric_builder::send(buf, ms); } std::expected send_values_array(std::initializer_list values, k2::MonitoringSystem ms, @@ -168,10 +168,10 @@ struct MetricBuilder final : vk::movable_only { auto buf{this->build_values_array(values, timestamp)}; for (const auto& tag : tags) { - MetricBuilder::store_tag(buf, tag); + metric_builder::store_tag(buf, tag); } - return MetricBuilder::send(buf, ms); + return metric_builder::send(buf, ms); } std::expected send_count(double count, k2::MonitoringSystem ms, std::initializer_list> tags = {}, @@ -180,10 +180,10 @@ struct MetricBuilder final : vk::movable_only { auto buf{this->build_count(count, timestamp)}; for (const auto& tag : tags) { - MetricBuilder::store_tag(buf, tag); + metric_builder::store_tag(buf, tag); } - return MetricBuilder::send(buf, ms); + return metric_builder::send(buf, ms); } std::expected send_increment(k2::MonitoringSystem ms, std::initializer_list> tags = {}, @@ -192,10 +192,10 @@ struct MetricBuilder final : vk::movable_only { auto buf{this->build_increment(timestamp)}; for (const auto& tag : tags) { - MetricBuilder::store_tag(buf, tag); + metric_builder::store_tag(buf, tag); } - return MetricBuilder::send(buf, ms); + return metric_builder::send(buf, ms); } }; } // namespace kphp::diagnostics From 064d8690f2c9078c40c4a0bb4174495eff87efb3 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 22 Jun 2026 17:03:45 +0300 Subject: [PATCH 09/48] add comments --- runtime-light/k2-platform/k2-header.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index da1592062c..3cfad1b3d0 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -402,11 +402,12 @@ 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). + * (see `MetricValueKind` 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. + * @return returns 0 if everything is fine, otherwise error_code */ int32_t k2_write_metric(const void* buf, size_t buf_len, enum MonitoringSystem ms); From de690e2872ed6febdafa37ce5cb71e08d312d6b7 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 22 Jun 2026 17:06:05 +0300 Subject: [PATCH 10/48] added noexcept --- runtime-light/stdlib/diagnostics/metrics.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 3f5e637248..54deb58afe 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -44,7 +44,7 @@ struct metric_builder final : vk::movable_only { static void store_string(bytes_vector& buf, const std::string_view& string) noexcept { metric_builder::store_number(buf, string.size()); - std::transform(string.begin(), string.end(), std::back_inserter(buf), [](char c) { return std::byte(c); }); + std::transform(string.begin(), string.end(), std::back_inserter(buf), [](char c) noexcept { return std::byte(c); }); } static void store_tag(bytes_vector& buf, std::pair tag) noexcept { From 127f856a29d6dc78393cd8fd4f31aa18a31120bd Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 22 Jun 2026 17:44:35 +0300 Subject: [PATCH 11/48] fixes --- runtime-light/k2-platform/k2-header.h | 2 +- runtime-light/stdlib/diagnostics/metrics.h | 41 +++++++++++----------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index 3cfad1b3d0..083d27b85b 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -106,7 +106,7 @@ enum MonitoringSystem { StatsHouse }; * value_format: * - single float value * ... - array of float values - * - count value + * - count value * - counter increment * * msg_size: sizeof(metric_name_len) + sizeof(metric_name) + sizeof(tag1_name_len) + sizeof(tag1_name) + sizeof(tag1_value_len) + sizeof(tag1_value) + ... diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 54deb58afe..80d814adb5 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -8,8 +8,8 @@ #include #include #include -#include #include +#include #include #include "common/containers/final_action.h" @@ -29,9 +29,11 @@ struct metric_builder final : vk::movable_only { kphp::memory::script_allocator> tags; size_t msg_size{0}; + k2::MonitoringSystem ms; - explicit metric_builder(std::string_view metric_name) noexcept - : metric_name{metric_name} { + explicit metric_builder(std::string_view metric_name, k2::MonitoringSystem ms) noexcept + : metric_name{metric_name}, + ms{ms} { this->msg_size += metric_builder::string_sizeof(metric_name); } @@ -44,7 +46,7 @@ struct metric_builder final : vk::movable_only { static void store_string(bytes_vector& buf, const std::string_view& string) noexcept { metric_builder::store_number(buf, string.size()); - std::transform(string.begin(), string.end(), std::back_inserter(buf), [](char c) noexcept { return std::byte(c); }); + buf.append_range(std::as_bytes(std::span{string.data(), string.size()})); } static void store_tag(bytes_vector& buf, std::pair tag) noexcept { @@ -60,7 +62,7 @@ struct metric_builder final : vk::movable_only { } } - auto send_helper(const std::initializer_list>& tags) noexcept { + auto send_helper(const std::span>& tags) noexcept { size_t tags_size{}; for (const auto& [tag_name, tag_value] : tags) { tags_size += metric_builder::string_sizeof(tag_name) + metric_builder::string_sizeof(tag_value); @@ -82,8 +84,8 @@ struct metric_builder final : vk::movable_only { return k2::write_metric(std::span{buf.data(), buf.size()}, ms); } - static metric_builder metric(std::string_view metric_name) noexcept { - return metric_builder{metric_name}; + static metric_builder metric(std::string_view metric_name, k2::MonitoringSystem ms) noexcept { + return metric_builder{metric_name, ms}; } metric_builder& tag(std::string_view tag_name, std::string_view tag_value) noexcept { @@ -106,7 +108,7 @@ struct metric_builder final : vk::movable_only { return buf; } - bytes_vector build_values_array(std::initializer_list values, std::optional timestamp = std::nullopt) const noexcept { + bytes_vector build_values_array(std::span values, std::optional 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_kind_u8 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len @@ -123,10 +125,10 @@ struct metric_builder final : vk::movable_only { return buf; } - bytes_vector build_count(double count, std::optional timestamp = std::nullopt) const noexcept { + bytes_vector build_count(uint32_t count, std::optional 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_kind_u8 + count_f64 + msg_size_usize + msg_len + buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + + this->msg_size); // timestamp_u32 + value_kind_u8 + count_u32 + msg_size_usize + msg_len uint32_t s_timestamp{timestamp.value_or(metric_builder::s_timestamp_now())}; @@ -149,7 +151,7 @@ struct metric_builder final : vk::movable_only { return buf; } - std::expected send_value(double value, k2::MonitoringSystem ms, std::initializer_list> tags = {}, + std::expected send_value(double value, std::span> tags = {}, std::optional timestamp = std::nullopt) noexcept { auto final_action{send_helper(tags)}; @@ -158,11 +160,10 @@ struct metric_builder final : vk::movable_only { metric_builder::store_tag(buf, tag); } - return metric_builder::send(buf, ms); + return metric_builder::send(buf, this->ms); } - std::expected send_values_array(std::initializer_list values, k2::MonitoringSystem ms, - std::initializer_list> tags = {}, + std::expected send_values_array(std::span values, std::span> tags = {}, std::optional timestamp = std::nullopt) noexcept { auto final_action{send_helper(tags)}; @@ -171,10 +172,10 @@ struct metric_builder final : vk::movable_only { metric_builder::store_tag(buf, tag); } - return metric_builder::send(buf, ms); + return metric_builder::send(buf, this->ms); } - std::expected send_count(double count, k2::MonitoringSystem ms, std::initializer_list> tags = {}, + std::expected send_count(uint32_t count, std::span> tags = {}, std::optional timestamp = std::nullopt) noexcept { auto final_action{send_helper(tags)}; @@ -183,10 +184,10 @@ struct metric_builder final : vk::movable_only { metric_builder::store_tag(buf, tag); } - return metric_builder::send(buf, ms); + return metric_builder::send(buf, this->ms); } - std::expected send_increment(k2::MonitoringSystem ms, std::initializer_list> tags = {}, + std::expected send_increment(std::span> tags = {}, std::optional timestamp = std::nullopt) noexcept { auto final_action{send_helper(tags)}; @@ -195,7 +196,7 @@ struct metric_builder final : vk::movable_only { metric_builder::store_tag(buf, tag); } - return metric_builder::send(buf, ms); + return metric_builder::send(buf, this->ms); } }; } // namespace kphp::diagnostics From 537b967614f2284bc3b3ef46fed6ca03cc2f19b2 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 22 Jun 2026 17:46:14 +0300 Subject: [PATCH 12/48] minor fix --- runtime-light/k2-platform/k2-header.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index 083d27b85b..c2830635e6 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -407,7 +407,7 @@ int32_t k2_madvise(void* addr, size_t length, int32_t advise); * @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. - * @return returns 0 if everything is fine, otherwise error_code + * @return returns 0 if everything is fine, otherwise error code */ int32_t k2_write_metric(const void* buf, size_t buf_len, enum MonitoringSystem ms); From 22a62271eec8efdb210cf571728a0df130fe2d02 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 22 Jun 2026 19:23:46 +0300 Subject: [PATCH 13/48] added metric type --- runtime-light/k2-platform/k2-api.h | 2 +- runtime-light/stdlib/diagnostics/metrics.h | 233 +++++++++++---------- 2 files changed, 128 insertions(+), 107 deletions(-) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index b7f046ed69..3744999062 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -249,7 +249,7 @@ inline std::expected madvise(void* addr, size_t length, int32_t a return {}; } -inline std::expected write_metric(const std::span serialized_metric, k2::MonitoringSystem ms) noexcept { +inline std::expected write_metric(const std::span serialized_metric, k2::MonitoringSystem ms) noexcept { if (auto error_code{k2_write_metric(serialized_metric.data(), serialized_metric.size(), ms)}; error_code != k2::errno_ok) { return std::unexpected{error_code}; } diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 80d814adb5..14cba39765 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -9,33 +9,27 @@ #include #include #include +#include #include #include +#include -#include "common/containers/final_action.h" -#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" namespace kphp::diagnostics { -struct metric_builder final : vk::movable_only { +struct metric final { public: using bytes_vector = kphp::stl::vector; private: - kphp::stl::string metric_name; - kphp::stl::vector, kphp::stl::string>, - kphp::memory::script_allocator> - tags; - size_t msg_size{0}; + const bytes_vector buffer; k2::MonitoringSystem ms; - explicit metric_builder(std::string_view metric_name, k2::MonitoringSystem ms) noexcept - : metric_name{metric_name}, - ms{ms} { - this->msg_size += metric_builder::string_sizeof(metric_name); - } + explicit metric(bytes_vector buffer, k2::MonitoringSystem ms) noexcept + : buffer{std::move(buffer)}, + ms{ms} {} template requires std::is_arithmetic_v @@ -45,30 +39,22 @@ struct metric_builder final : vk::movable_only { } static void store_string(bytes_vector& buf, const std::string_view& string) noexcept { - metric_builder::store_number(buf, string.size()); + metric::store_number(buf, string.size()); buf.append_range(std::as_bytes(std::span{string.data(), string.size()})); } - static void store_tag(bytes_vector& buf, std::pair tag) noexcept { - metric_builder::store_string(buf, tag.first); - metric_builder::store_string(buf, tag.second); + static void store_tag(bytes_vector& buf, std::string_view tag_name, std::string_view tag_value) noexcept { + metric::store_string(buf, tag_name); + metric::store_string(buf, tag_value); } - void store_msg(bytes_vector& buf) const noexcept { - metric_builder::store_number(buf, this->msg_size); - metric_builder::store_string(buf, std::string_view{this->metric_name.c_str(), this->metric_name.size()}); - for (const auto& [tag_name, tag_value] : this->tags) { - metric_builder::store_tag(buf, {std::string_view{tag_name.c_str(), tag_name.size()}, std::string_view{tag_value.c_str(), tag_value.size()}}); - } - } - - auto send_helper(const std::span>& tags) noexcept { - size_t tags_size{}; + static void store_msg(bytes_vector& buf, std::string_view metric_name, size_t msg_size, + std::span> tags) noexcept { + metric::store_number(buf, msg_size); + metric::store_string(buf, metric_name); for (const auto& [tag_name, tag_value] : tags) { - tags_size += metric_builder::string_sizeof(tag_name) + metric_builder::string_sizeof(tag_value); + metric::store_tag(buf, tag_name, tag_value); } - this->msg_size += tags_size; - return vk::final_action{[tags_size, this]() noexcept { this->msg_size -= tags_size; }}; } static size_t string_sizeof(const std::string_view& string) noexcept { @@ -79,124 +65,159 @@ struct metric_builder final : vk::movable_only { return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); } -public: - static std::expected send(bytes_vector& buf, k2::MonitoringSystem ms) noexcept { - return k2::write_metric(std::span{buf.data(), buf.size()}, ms); - } - - static metric_builder metric(std::string_view metric_name, k2::MonitoringSystem ms) noexcept { - return metric_builder{metric_name, ms}; + static size_t calc_msg_size(std::string_view metric_name, std::span> tags) noexcept { + size_t result{string_sizeof(metric_name)}; + for (const auto& [tag_name, tag_value] : tags) { + result += metric::string_sizeof(tag_name) + metric::string_sizeof(tag_value); + } + return result; } - metric_builder& tag(std::string_view tag_name, std::string_view tag_value) noexcept { - this->tags.emplace_back(tag_name, tag_value); - this->msg_size += metric_builder::string_sizeof(tag_name) + metric_builder::string_sizeof(tag_value); - return *this; - } +public: + static metric from_value(k2::MonitoringSystem ms, std::string_view metric_name, std::span> tags, double value, + std::optional timestamp = std::nullopt) noexcept { + size_t msg_size{metric::calc_msg_size(metric_name, tags)}; - bytes_vector build_value(double value, std::optional 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_kind_u8 + value_f64 + msg_size_usize + msg_len + msg_size); // timestamp_u32 + value_kind_u8 + value_f64 + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(metric_builder::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(metric::s_timestamp_now())}; - metric_builder::store_number(buf, s_timestamp); - metric_builder::store_number(buf, static_cast(k2::MetricValueKind::VALUE)); - metric_builder::store_number(buf, value); - this->store_msg(buf); - return buf; + metric::store_number(buf, s_timestamp); + metric::store_number(buf, static_cast(k2::MetricValueKind::VALUE)); + metric::store_number(buf, value); + metric::store_msg(buf, metric_name, msg_size, tags); + return metric{buf, ms}; } - bytes_vector build_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { + static metric from_values_array(k2::MonitoringSystem ms, std::string_view metric_name, std::span> tags, + std::span values, std::optional timestamp = std::nullopt) noexcept { + size_t msg_size{metric::calc_msg_size(metric_name, tags)}; + 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_kind_u8 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len + msg_size); // timestamp_u32 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(metric_builder::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(metric::s_timestamp_now())}; - metric_builder::store_number(buf, s_timestamp); - metric_builder::store_number(buf, static_cast(k2::MetricValueKind::VALUES_ARRAY)); - metric_builder::store_number(buf, values.size()); + metric::store_number(buf, s_timestamp); + metric::store_number(buf, static_cast(k2::MetricValueKind::VALUES_ARRAY)); + metric::store_number(buf, values.size()); for (const auto& value : values) { - metric_builder::store_number(buf, value); + metric::store_number(buf, value); } - this->store_msg(buf); - return buf; + metric::store_msg(buf, metric_name, msg_size, tags); + return metric{buf, ms}; } - bytes_vector build_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { + static metric from_count(k2::MonitoringSystem ms, std::string_view metric_name, std::span> tags, uint32_t count, + std::optional timestamp = std::nullopt) noexcept { + size_t msg_size{metric::calc_msg_size(metric_name, tags)}; + bytes_vector buf{}; buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + - this->msg_size); // timestamp_u32 + value_kind_u8 + count_u32 + msg_size_usize + msg_len + msg_size); // timestamp_u32 + value_kind_u8 + count_u32 + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(metric_builder::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(metric::s_timestamp_now())}; - metric_builder::store_number(buf, s_timestamp); - metric_builder::store_number(buf, static_cast(k2::MetricValueKind::COUNT)); - metric_builder::store_number(buf, count); - this->store_msg(buf); - return buf; + metric::store_number(buf, s_timestamp); + metric::store_number(buf, static_cast(k2::MetricValueKind::COUNT)); + metric::store_number(buf, count); + metric::store_msg(buf, metric_name, msg_size, tags); + + return metric{buf, ms}; } - bytes_vector build_increment(std::optional timestamp = std::nullopt) const noexcept { + static metric from_increment(k2::MonitoringSystem ms, std::string_view metric_name, std::span> tags, + std::optional timestamp = std::nullopt) noexcept { + size_t msg_size{metric::calc_msg_size(metric_name, tags)}; + bytes_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_kind_u8 + msg_size_usize + msg_len + buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + msg_size); // timestamp_u32 + value_kind_u8 + msg_size_usize + msg_len - uint32_t s_timestamp{timestamp.value_or(metric_builder::s_timestamp_now())}; + uint32_t s_timestamp{timestamp.value_or(metric::s_timestamp_now())}; - metric_builder::store_number(buf, s_timestamp); - metric_builder::store_number(buf, static_cast(k2::MetricValueKind::INC)); - this->store_msg(buf); - return buf; + metric::store_number(buf, s_timestamp); + metric::store_number(buf, static_cast(k2::MetricValueKind::INC)); + metric::store_msg(buf, metric_name, msg_size, tags); + return metric{buf, ms}; } - std::expected send_value(double value, std::span> tags = {}, - std::optional timestamp = std::nullopt) noexcept { - auto final_action{send_helper(tags)}; + std::expected send() { + return k2::write_metric(this->buffer, this->ms); + } +}; - auto buf{this->build_value(value, timestamp)}; - for (const auto& tag : tags) { - metric_builder::store_tag(buf, tag); - } +// --------------------------------------------------------------------------------------------------------- - return metric_builder::send(buf, this->ms); +struct metric_builder final { +public: + using bytes_vector = kphp::stl::vector; + +private: + kphp::stl::string metric_name; + kphp::stl::vector, kphp::stl::string>, + kphp::memory::script_allocator> + tags; + size_t msg_size{0}; + k2::MonitoringSystem ms; + + explicit metric_builder(std::string_view metric_name, k2::MonitoringSystem ms) noexcept + : metric_name{metric_name}, + ms{ms} { + this->msg_size += metric_builder::string_sizeof(metric_name); } - std::expected send_values_array(std::span values, std::span> tags = {}, - std::optional timestamp = std::nullopt) noexcept { - auto final_action{send_helper(tags)}; + kphp::stl::vector, kphp::memory::script_allocator> convert_tags() const noexcept { + auto tags_view{this->tags | + std::views::transform( + [](const std::pair, kphp::stl::string>& tag) noexcept + -> std::pair { return std::pair{tag.first, tag.second}; })}; - auto buf{this->build_values_array(values, timestamp)}; - for (const auto& tag : tags) { - metric_builder::store_tag(buf, tag); - } + kphp::stl::vector, kphp::memory::script_allocator> tags{}; + tags.reserve(this->tags.size()); + std::ranges::copy(tags_view, std::back_inserter(tags)); + return tags; + } - return metric_builder::send(buf, this->ms); + static size_t string_sizeof(const std::string_view& string) noexcept { + return sizeof(size_t) + string.size(); } - std::expected send_count(uint32_t count, std::span> tags = {}, - std::optional timestamp = std::nullopt) noexcept { - auto final_action{send_helper(tags)}; +public: + static std::expected send(bytes_vector& buf, k2::MonitoringSystem ms) noexcept { + return k2::write_metric(std::span{buf.data(), buf.size()}, ms); + } - auto buf{this->build_count(count, timestamp)}; - for (const auto& tag : tags) { - metric_builder::store_tag(buf, tag); - } + static metric_builder metric(std::string_view metric_name, k2::MonitoringSystem ms) noexcept { + return metric_builder{metric_name, ms}; + } - return metric_builder::send(buf, this->ms); + metric_builder& tag(std::string_view tag_name, std::string_view tag_value) noexcept { + this->tags.emplace_back(tag_name, tag_value); + this->msg_size += metric_builder::string_sizeof(tag_name) + metric_builder::string_sizeof(tag_value); + return *this; + } + + kphp::diagnostics::metric build_value(double value, std::optional timestamp = std::nullopt) const noexcept { + auto sv_tags{this->convert_tags()}; + return metric::from_value(this->ms, this->metric_name, sv_tags, value, timestamp); } - std::expected send_increment(std::span> tags = {}, - std::optional timestamp = std::nullopt) noexcept { - auto final_action{send_helper(tags)}; + kphp::diagnostics::metric build_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { + auto sv_tags{this->convert_tags()}; + return metric::from_values_array(this->ms, this->metric_name, sv_tags, values, timestamp); + } - auto buf{this->build_increment(timestamp)}; - for (const auto& tag : tags) { - metric_builder::store_tag(buf, tag); - } + kphp::diagnostics::metric build_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { + auto sv_tags{this->convert_tags()}; + return metric::from_count(this->ms, this->metric_name, sv_tags, count, timestamp); + } - return metric_builder::send(buf, this->ms); + kphp::diagnostics::metric build_increment(std::optional timestamp = std::nullopt) const noexcept { + auto sv_tags{this->convert_tags()}; + return metric::from_increment(this->ms, this->metric_name, sv_tags, timestamp); } }; } // namespace kphp::diagnostics From 86f1de84e3a2f72d5a9c9bbcaa179fbb59aa081b Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 00:00:09 +0300 Subject: [PATCH 14/48] fixes --- runtime-light/k2-platform/k2-api.h | 2 +- runtime-light/k2-platform/k2-header.h | 3 + runtime-light/stdlib/diagnostics/metrics.h | 100 +++++++++------------ 3 files changed, 45 insertions(+), 60 deletions(-) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 3744999062..933607c416 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -250,7 +250,7 @@ inline std::expected madvise(void* addr, size_t length, int32_t a } inline std::expected write_metric(const std::span serialized_metric, k2::MonitoringSystem ms) noexcept { - if (auto error_code{k2_write_metric(serialized_metric.data(), serialized_metric.size(), ms)}; error_code != k2::errno_ok) { + if (auto error_code{k2_write_metric(serialized_metric.data(), serialized_metric.size(), ms)}; error_code != k2::errno_ok) [[unlikely]] { return std::unexpected{error_code}; } return {}; diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index c2830635e6..1b263c0d02 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -110,6 +110,9 @@ enum MonitoringSystem { StatsHouse }; * - counter increment * * msg_size: sizeof(metric_name_len) + sizeof(metric_name) + sizeof(tag1_name_len) + sizeof(tag1_name) + sizeof(tag1_value_len) + sizeof(tag1_value) + ... + * + * All numeric fields are stored in native byte order + * All string length fields are stored as size_t */ enum MetricValueKind : uint8_t { VALUE, VALUES_ARRAY, COUNT, INC }; diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 14cba39765..233dbd3f7a 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -19,11 +19,23 @@ #include "runtime-light/k2-platform/k2-api.h" namespace kphp::diagnostics { + +namespace details { +inline size_t string_sizeof(const std::string_view& string) noexcept { + return sizeof(size_t) + string.size(); +} + +template +concept tag_range = std::ranges::range && requires(const std::ranges::range_value_t& tag) { + std::string_view{tag.first}; + std::string_view{tag.second}; +}; +} // namespace details + struct metric final { -public: +private: using bytes_vector = kphp::stl::vector; -private: const bytes_vector buffer; k2::MonitoringSystem ms; @@ -48,33 +60,31 @@ struct metric final { metric::store_string(buf, tag_value); } - static void store_msg(bytes_vector& buf, std::string_view metric_name, size_t msg_size, - std::span> tags) noexcept { + template + static void store_msg(bytes_vector& buf, std::string_view metric_name, size_t msg_size, TagRange&& tags) noexcept { metric::store_number(buf, msg_size); metric::store_string(buf, metric_name); for (const auto& [tag_name, tag_value] : tags) { - metric::store_tag(buf, tag_name, tag_value); + metric::store_tag(buf, std::string_view{tag_name}, std::string_view{tag_value}); } } - 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::system_clock::now().time_since_epoch()).count(); } - static size_t calc_msg_size(std::string_view metric_name, std::span> tags) noexcept { - size_t result{string_sizeof(metric_name)}; + template + static size_t calc_msg_size(std::string_view metric_name, TagRange&& tags) noexcept { + size_t result{kphp::diagnostics::details::string_sizeof(metric_name)}; for (const auto& [tag_name, tag_value] : tags) { - result += metric::string_sizeof(tag_name) + metric::string_sizeof(tag_value); + result += kphp::diagnostics::details::string_sizeof(std::string_view{tag_name}) + kphp::diagnostics::details::string_sizeof(std::string_view{tag_value}); } return result; } public: - static metric from_value(k2::MonitoringSystem ms, std::string_view metric_name, std::span> tags, double value, + template + static metric from_value(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { size_t msg_size{metric::calc_msg_size(metric_name, tags)}; @@ -88,11 +98,12 @@ struct metric final { metric::store_number(buf, static_cast(k2::MetricValueKind::VALUE)); metric::store_number(buf, value); metric::store_msg(buf, metric_name, msg_size, tags); - return metric{buf, ms}; + return metric{std::move(buf), ms}; } - static metric from_values_array(k2::MonitoringSystem ms, std::string_view metric_name, std::span> tags, - std::span values, std::optional timestamp = std::nullopt) noexcept { + template + static metric from_values_array(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, std::span values, + std::optional timestamp = std::nullopt) noexcept { size_t msg_size{metric::calc_msg_size(metric_name, tags)}; bytes_vector buf{}; @@ -108,10 +119,11 @@ struct metric final { metric::store_number(buf, value); } metric::store_msg(buf, metric_name, msg_size, tags); - return metric{buf, ms}; + return metric{std::move(buf), ms}; } - static metric from_count(k2::MonitoringSystem ms, std::string_view metric_name, std::span> tags, uint32_t count, + template + static metric from_count(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { size_t msg_size{metric::calc_msg_size(metric_name, tags)}; @@ -126,10 +138,11 @@ struct metric final { metric::store_number(buf, count); metric::store_msg(buf, metric_name, msg_size, tags); - return metric{buf, ms}; + return metric{std::move(buf), ms}; } - static metric from_increment(k2::MonitoringSystem ms, std::string_view metric_name, std::span> tags, + template + static metric from_increment(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { size_t msg_size{metric::calc_msg_size(metric_name, tags)}; @@ -141,10 +154,10 @@ struct metric final { metric::store_number(buf, s_timestamp); metric::store_number(buf, static_cast(k2::MetricValueKind::INC)); metric::store_msg(buf, metric_name, msg_size, tags); - return metric{buf, ms}; + return metric{std::move(buf), ms}; } - std::expected send() { + std::expected send() noexcept { return k2::write_metric(this->buffer, this->ms); } }; @@ -152,72 +165,41 @@ struct metric final { // --------------------------------------------------------------------------------------------------------- struct metric_builder final { -public: - using bytes_vector = kphp::stl::vector; - private: kphp::stl::string metric_name; kphp::stl::vector, kphp::stl::string>, kphp::memory::script_allocator> tags; - size_t msg_size{0}; k2::MonitoringSystem ms; explicit metric_builder(std::string_view metric_name, k2::MonitoringSystem ms) noexcept : metric_name{metric_name}, - ms{ms} { - this->msg_size += metric_builder::string_sizeof(metric_name); - } - - kphp::stl::vector, kphp::memory::script_allocator> convert_tags() const noexcept { - auto tags_view{this->tags | - std::views::transform( - [](const std::pair, kphp::stl::string>& tag) noexcept - -> std::pair { return std::pair{tag.first, tag.second}; })}; - - kphp::stl::vector, kphp::memory::script_allocator> tags{}; - tags.reserve(this->tags.size()); - std::ranges::copy(tags_view, std::back_inserter(tags)); - return tags; - } - - static size_t string_sizeof(const std::string_view& string) noexcept { - return sizeof(size_t) + string.size(); - } + ms{ms} {} public: - static std::expected send(bytes_vector& buf, k2::MonitoringSystem ms) noexcept { - return k2::write_metric(std::span{buf.data(), buf.size()}, ms); - } - static metric_builder metric(std::string_view metric_name, k2::MonitoringSystem ms) noexcept { return metric_builder{metric_name, ms}; } metric_builder& tag(std::string_view tag_name, std::string_view tag_value) noexcept { this->tags.emplace_back(tag_name, tag_value); - this->msg_size += metric_builder::string_sizeof(tag_name) + metric_builder::string_sizeof(tag_value); return *this; } kphp::diagnostics::metric build_value(double value, std::optional timestamp = std::nullopt) const noexcept { - auto sv_tags{this->convert_tags()}; - return metric::from_value(this->ms, this->metric_name, sv_tags, value, timestamp); + return metric::from_value(this->ms, this->metric_name, this->tags, value, timestamp); } - kphp::diagnostics::metric build_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - auto sv_tags{this->convert_tags()}; - return metric::from_values_array(this->ms, this->metric_name, sv_tags, values, timestamp); + kphp::diagnostics::metric build_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { + return metric::from_values_array(this->ms, this->metric_name, this->tags, values, timestamp); } kphp::diagnostics::metric build_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { - auto sv_tags{this->convert_tags()}; - return metric::from_count(this->ms, this->metric_name, sv_tags, count, timestamp); + return metric::from_count(this->ms, this->metric_name, this->tags, count, timestamp); } kphp::diagnostics::metric build_increment(std::optional timestamp = std::nullopt) const noexcept { - auto sv_tags{this->convert_tags()}; - return metric::from_increment(this->ms, this->metric_name, sv_tags, timestamp); + return metric::from_increment(this->ms, this->metric_name, this->tags, timestamp); } }; } // namespace kphp::diagnostics From 22cdf8559085859343ded2f55c2a6f85058c1357 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 14:38:38 +0300 Subject: [PATCH 15/48] timestamp u32 to u64 + fixes --- runtime-light/k2-platform/k2-api.h | 2 +- runtime-light/k2-platform/k2-header.h | 6 +- runtime-light/stdlib/diagnostics/metrics.h | 80 +++++++++++----------- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 933607c416..1480d15576 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -249,7 +249,7 @@ inline std::expected madvise(void* addr, size_t length, int32_t a return {}; } -inline std::expected write_metric(const std::span serialized_metric, k2::MonitoringSystem ms) noexcept { +inline std::expected write_metric(std::span serialized_metric, k2::MonitoringSystem ms) noexcept { if (auto error_code{k2_write_metric(serialized_metric.data(), serialized_metric.size(), ms)}; error_code != k2::errno_ok) [[unlikely]] { return std::unexpected{error_code}; } diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index 1b263c0d02..6c7347aa8a 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -101,7 +101,7 @@ enum MonitoringSystem { StatsHouse }; /* * Serialized metric format: - * ... + * ... * * value_format: * - single float value @@ -109,10 +109,10 @@ enum MonitoringSystem { StatsHouse }; * - count value * - counter increment * - * msg_size: sizeof(metric_name_len) + sizeof(metric_name) + sizeof(tag1_name_len) + sizeof(tag1_name) + sizeof(tag1_value_len) + sizeof(tag1_value) + ... + * msg_len: sizeof(metric_name_len) + len(metric_name) + sizeof(tag1_name_len) + len(tag1_name) + sizeof(tag1_value_len) + len(tag1_value) + ... * * All numeric fields are stored in native byte order - * All string length fields are stored as size_t + * All string length fields (*_len) are stored as size_t */ enum MetricValueKind : uint8_t { VALUE, VALUES_ARRAY, COUNT, INC }; diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 233dbd3f7a..ae697c77a7 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -39,7 +39,7 @@ struct metric final { const bytes_vector buffer; k2::MonitoringSystem ms; - explicit metric(bytes_vector buffer, k2::MonitoringSystem ms) noexcept + metric(bytes_vector buffer, k2::MonitoringSystem ms) noexcept : buffer{std::move(buffer)}, ms{ms} {} @@ -61,22 +61,22 @@ struct metric final { } template - static void store_msg(bytes_vector& buf, std::string_view metric_name, size_t msg_size, TagRange&& tags) noexcept { - metric::store_number(buf, msg_size); + static void store_msg(bytes_vector& buf, std::string_view metric_name, size_t msg_len, TagRange&& tags) noexcept { + metric::store_number(buf, msg_len); metric::store_string(buf, metric_name); - for (const auto& [tag_name, tag_value] : tags) { + for (const auto& [tag_name, tag_value] : std::forward(tags)) { metric::store_tag(buf, std::string_view{tag_name}, std::string_view{tag_value}); } } - static uint32_t s_timestamp_now() noexcept { - return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + static uint64_t ns_timestamp_now() noexcept { + return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); } template - static size_t calc_msg_size(std::string_view metric_name, TagRange&& tags) noexcept { + static size_t calc_msg_len(std::string_view metric_name, TagRange&& tags) noexcept { size_t result{kphp::diagnostics::details::string_sizeof(metric_name)}; - for (const auto& [tag_name, tag_value] : tags) { + for (const auto& [tag_name, tag_value] : std::forward(tags)) { result += kphp::diagnostics::details::string_sizeof(std::string_view{tag_name}) + kphp::diagnostics::details::string_sizeof(std::string_view{tag_value}); } return result; @@ -85,79 +85,77 @@ struct metric final { public: template static metric from_value(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, double value, - std::optional timestamp = std::nullopt) noexcept { - size_t msg_size{metric::calc_msg_size(metric_name, tags)}; + std::optional timestamp = std::nullopt) noexcept { + size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; bytes_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + - msg_size); // timestamp_u32 + value_kind_u8 + value_f64 + msg_size_usize + msg_len + buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + value_f64 + msg_len + msg - uint32_t s_timestamp{timestamp.value_or(metric::s_timestamp_now())}; + uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - metric::store_number(buf, s_timestamp); + metric::store_number(buf, ns_timestamp); metric::store_number(buf, static_cast(k2::MetricValueKind::VALUE)); metric::store_number(buf, value); - metric::store_msg(buf, metric_name, msg_size, tags); + metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); return metric{std::move(buf), ms}; } template static metric from_values_array(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, std::span values, - std::optional timestamp = std::nullopt) noexcept { - size_t msg_size{metric::calc_msg_size(metric_name, tags)}; + std::optional timestamp = std::nullopt) noexcept { + size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; bytes_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + - msg_size); // timestamp_u32 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len + buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + + msg_len); // timestamp_u64 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_len + msg - uint32_t s_timestamp{timestamp.value_or(metric::s_timestamp_now())}; + uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - metric::store_number(buf, s_timestamp); + metric::store_number(buf, ns_timestamp); metric::store_number(buf, static_cast(k2::MetricValueKind::VALUES_ARRAY)); metric::store_number(buf, values.size()); for (const auto& value : values) { metric::store_number(buf, value); } - metric::store_msg(buf, metric_name, msg_size, tags); + metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); return metric{std::move(buf), ms}; } template static metric from_count(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, uint32_t count, - std::optional timestamp = std::nullopt) noexcept { - size_t msg_size{metric::calc_msg_size(metric_name, tags)}; + std::optional timestamp = std::nullopt) noexcept { + size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; bytes_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + - msg_size); // timestamp_u32 + value_kind_u8 + count_u32 + msg_size_usize + msg_len + buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + count_u32 + msg_len + msg - uint32_t s_timestamp{timestamp.value_or(metric::s_timestamp_now())}; + uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - metric::store_number(buf, s_timestamp); + metric::store_number(buf, ns_timestamp); metric::store_number(buf, static_cast(k2::MetricValueKind::COUNT)); metric::store_number(buf, count); - metric::store_msg(buf, metric_name, msg_size, tags); + metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); return metric{std::move(buf), ms}; } template static metric from_increment(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, - std::optional timestamp = std::nullopt) noexcept { - size_t msg_size{metric::calc_msg_size(metric_name, tags)}; + std::optional timestamp = std::nullopt) noexcept { + size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; bytes_vector buf{}; - buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + msg_size); // timestamp_u32 + value_kind_u8 + msg_size_usize + msg_len + buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + msg_len + msg - uint32_t s_timestamp{timestamp.value_or(metric::s_timestamp_now())}; + uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - metric::store_number(buf, s_timestamp); + metric::store_number(buf, ns_timestamp); metric::store_number(buf, static_cast(k2::MetricValueKind::INC)); - metric::store_msg(buf, metric_name, msg_size, tags); + metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); return metric{std::move(buf), ms}; } - std::expected send() noexcept { + std::expected send() const noexcept { return k2::write_metric(this->buffer, this->ms); } }; @@ -172,7 +170,7 @@ struct metric_builder final { tags; k2::MonitoringSystem ms; - explicit metric_builder(std::string_view metric_name, k2::MonitoringSystem ms) noexcept + metric_builder(std::string_view metric_name, k2::MonitoringSystem ms) noexcept : metric_name{metric_name}, ms{ms} {} @@ -186,19 +184,19 @@ struct metric_builder final { return *this; } - kphp::diagnostics::metric build_value(double value, std::optional timestamp = std::nullopt) const noexcept { + kphp::diagnostics::metric build_value(double value, std::optional timestamp = std::nullopt) const noexcept { return metric::from_value(this->ms, this->metric_name, this->tags, value, timestamp); } - kphp::diagnostics::metric build_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { + kphp::diagnostics::metric build_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { return metric::from_values_array(this->ms, this->metric_name, this->tags, values, timestamp); } - kphp::diagnostics::metric build_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { + kphp::diagnostics::metric build_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { return metric::from_count(this->ms, this->metric_name, this->tags, count, timestamp); } - kphp::diagnostics::metric build_increment(std::optional timestamp = std::nullopt) const noexcept { + kphp::diagnostics::metric build_increment(std::optional timestamp = std::nullopt) const noexcept { return metric::from_increment(this->ms, this->metric_name, this->tags, timestamp); } }; From 21e5bdb2bf05e3a7bb60cb04ca9ef9c6d93dc3a5 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 15:16:46 +0300 Subject: [PATCH 16/48] fix --- runtime-light/stdlib/diagnostics/metrics.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index ae697c77a7..d74b18f00a 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -24,13 +24,13 @@ namespace details { inline size_t string_sizeof(const std::string_view& string) noexcept { return sizeof(size_t) + string.size(); } +} // namespace details template concept tag_range = std::ranges::range && requires(const std::ranges::range_value_t& tag) { std::string_view{tag.first}; std::string_view{tag.second}; }; -} // namespace details struct metric final { private: From 88709e2213aa9cadce09b6de4c6f995b85b93e6a Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 15:18:47 +0300 Subject: [PATCH 17/48] fix --- runtime-light/stdlib/diagnostics/metrics.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index d74b18f00a..553bbc08b8 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -60,7 +60,7 @@ struct metric final { metric::store_string(buf, tag_value); } - template + template static void store_msg(bytes_vector& buf, std::string_view metric_name, size_t msg_len, TagRange&& tags) noexcept { metric::store_number(buf, msg_len); metric::store_string(buf, metric_name); @@ -73,7 +73,7 @@ struct metric final { return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); } - template + template static size_t calc_msg_len(std::string_view metric_name, TagRange&& tags) noexcept { size_t result{kphp::diagnostics::details::string_sizeof(metric_name)}; for (const auto& [tag_name, tag_value] : std::forward(tags)) { @@ -83,7 +83,7 @@ struct metric final { } public: - template + template static metric from_value(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; @@ -100,7 +100,7 @@ struct metric final { return metric{std::move(buf), ms}; } - template + template static metric from_values_array(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, std::span values, std::optional timestamp = std::nullopt) noexcept { size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; @@ -121,7 +121,7 @@ struct metric final { return metric{std::move(buf), ms}; } - template + template static metric from_count(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; @@ -139,7 +139,7 @@ struct metric final { return metric{std::move(buf), ms}; } - template + template static metric from_increment(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; From 45906628e9d18345628d63b5ca1fa0b0bce42fd0 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 15:24:14 +0300 Subject: [PATCH 18/48] fix concept --- runtime-light/stdlib/diagnostics/metrics.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 553bbc08b8..4c2986bbb6 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "runtime-common/core/allocator/script-allocator.h" @@ -27,10 +28,7 @@ inline size_t string_sizeof(const std::string_view& string) noexcept { } // namespace details template -concept tag_range = std::ranges::range && requires(const std::ranges::range_value_t& tag) { - std::string_view{tag.first}; - std::string_view{tag.second}; -}; +concept tag_range = std::ranges::range && std::is_convertible_v, std::pair>; struct metric final { private: From 6f3052d075994deec72eb1ed9c5ce4fa70c786cd Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 17:26:34 +0300 Subject: [PATCH 19/48] new metrics ctors --- runtime-light/stdlib/diagnostics/metrics.h | 81 ++++++++++++++-------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 4c2986bbb6..3258c9daf4 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include "runtime-common/core/allocator/script-allocator.h" #include "runtime-common/core/std/containers.h" #include "runtime-light/k2-platform/k2-api.h" +#include "runtime-light/stdlib/diagnostics/logs.h" namespace kphp::diagnostics { @@ -28,16 +30,21 @@ inline size_t string_sizeof(const std::string_view& string) noexcept { } // namespace details template -concept tag_range = std::ranges::range && std::is_convertible_v, std::pair>; +concept tag_range = std::ranges::range && std::is_constructible_v, std::ranges::range_value_t>; struct metric final { -private: +public: using bytes_vector = kphp::stl::vector; - const bytes_vector buffer; +private: + std::optional buffer; k2::MonitoringSystem ms; - metric(bytes_vector buffer, k2::MonitoringSystem ms) noexcept + explicit metric(k2::MonitoringSystem ms) noexcept + : buffer{bytes_vector{}}, + ms{ms} {} + + metric(bytes_vector&& buffer, k2::MonitoringSystem ms) noexcept : buffer{std::move(buffer)}, ms{ms} {} @@ -81,12 +88,20 @@ struct metric final { } public: + static metric initial(k2::MonitoringSystem ms) noexcept { + return metric{ms}; + } + + static metric with_buffer(bytes_vector& buffer, k2::MonitoringSystem ms) noexcept { + return metric{std::move(buffer), ms}; + } + template - static metric from_value(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, double value, - std::optional timestamp = std::nullopt) noexcept { - size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; + metric build_value(std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { + kphp::log::assertion(this->buffer.has_value()); + bytes_vector& buf{this->buffer.value()}; - bytes_vector buf{}; + size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + value_f64 + msg_len + msg uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; @@ -95,15 +110,16 @@ struct metric final { metric::store_number(buf, static_cast(k2::MetricValueKind::VALUE)); metric::store_number(buf, value); metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); - return metric{std::move(buf), ms}; + return *this; } template - static metric from_values_array(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, std::span values, - std::optional timestamp = std::nullopt) noexcept { - size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; + metric build_values_array(std::string_view metric_name, TagRange&& tags, std::span values, + std::optional timestamp = std::nullopt) noexcept { + kphp::log::assertion(this->buffer.has_value()); + bytes_vector& buf{this->buffer.value()}; - bytes_vector buf{}; + size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_len + msg @@ -116,15 +132,15 @@ struct metric final { metric::store_number(buf, value); } metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); - return metric{std::move(buf), ms}; + return *this; } template - static metric from_count(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, uint32_t count, - std::optional timestamp = std::nullopt) noexcept { - size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; + metric build_count(std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { + kphp::log::assertion(this->buffer.has_value()); + bytes_vector& buf{this->buffer.value()}; - bytes_vector buf{}; + size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + count_u32 + msg_len + msg uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; @@ -134,15 +150,15 @@ struct metric final { metric::store_number(buf, count); metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); - return metric{std::move(buf), ms}; + return *this; } template - static metric from_increment(k2::MonitoringSystem ms, std::string_view metric_name, TagRange&& tags, - std::optional timestamp = std::nullopt) noexcept { - size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; + metric build_increment(std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { + kphp::log::assertion(this->buffer.has_value()); + bytes_vector& buf{this->buffer.value()}; - bytes_vector buf{}; + size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + msg_len + msg uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; @@ -150,11 +166,18 @@ struct metric final { metric::store_number(buf, ns_timestamp); metric::store_number(buf, static_cast(k2::MetricValueKind::INC)); metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); - return metric{std::move(buf), ms}; + return *this; } std::expected send() const noexcept { - return k2::write_metric(this->buffer, this->ms); + kphp::log::assertion(this->buffer.has_value()); + return k2::write_metric(this->buffer.value(), this->ms); + } + + std::expected send() && noexcept { + kphp::log::assertion(this->buffer.has_value()); + bytes_vector& buf{this->buffer.value()}; + return k2::write_metric(buf, this->ms).transform([&buf]() noexcept { return std::move(buf); }); } }; @@ -183,19 +206,19 @@ struct metric_builder final { } kphp::diagnostics::metric build_value(double value, std::optional timestamp = std::nullopt) const noexcept { - return metric::from_value(this->ms, this->metric_name, this->tags, value, timestamp); + return metric::initial(this->ms).build_value(this->metric_name, this->tags, value, timestamp); } kphp::diagnostics::metric build_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - return metric::from_values_array(this->ms, this->metric_name, this->tags, values, timestamp); + return metric::initial(this->ms).build_values_array(this->metric_name, this->tags, values, timestamp); } kphp::diagnostics::metric build_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { - return metric::from_count(this->ms, this->metric_name, this->tags, count, timestamp); + return metric::initial(this->ms).build_count(this->metric_name, this->tags, count, timestamp); } kphp::diagnostics::metric build_increment(std::optional timestamp = std::nullopt) const noexcept { - return metric::from_increment(this->ms, this->metric_name, this->tags, timestamp); + return metric::initial(this->ms).build_increment(this->metric_name, this->tags, timestamp); } }; } // namespace kphp::diagnostics From 57d6b2ed372685f015cddf2c4e333216f56ecf3e Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 17:31:03 +0300 Subject: [PATCH 20/48] rename static method --- runtime-light/stdlib/diagnostics/metrics.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 3258c9daf4..30f2c8b3ad 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -88,7 +88,7 @@ struct metric final { } public: - static metric initial(k2::MonitoringSystem ms) noexcept { + static metric empty(k2::MonitoringSystem ms) noexcept { return metric{ms}; } @@ -206,19 +206,19 @@ struct metric_builder final { } kphp::diagnostics::metric build_value(double value, std::optional timestamp = std::nullopt) const noexcept { - return metric::initial(this->ms).build_value(this->metric_name, this->tags, value, timestamp); + return metric::empty(this->ms).build_value(this->metric_name, this->tags, value, timestamp); } kphp::diagnostics::metric build_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - return metric::initial(this->ms).build_values_array(this->metric_name, this->tags, values, timestamp); + return metric::empty(this->ms).build_values_array(this->metric_name, this->tags, values, timestamp); } kphp::diagnostics::metric build_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { - return metric::initial(this->ms).build_count(this->metric_name, this->tags, count, timestamp); + return metric::empty(this->ms).build_count(this->metric_name, this->tags, count, timestamp); } kphp::diagnostics::metric build_increment(std::optional timestamp = std::nullopt) const noexcept { - return metric::initial(this->ms).build_increment(this->metric_name, this->tags, timestamp); + return metric::empty(this->ms).build_increment(this->metric_name, this->tags, timestamp); } }; } // namespace kphp::diagnostics From a5f3057d689318c142db4f2672a145e0fccadc9b Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 18:06:29 +0300 Subject: [PATCH 21/48] funny fixes --- runtime-light/stdlib/diagnostics/metrics.h | 120 ++++++++++----------- 1 file changed, 56 insertions(+), 64 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 30f2c8b3ad..80f3c7950c 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -19,7 +18,6 @@ #include "runtime-common/core/allocator/script-allocator.h" #include "runtime-common/core/std/containers.h" #include "runtime-light/k2-platform/k2-api.h" -#include "runtime-light/stdlib/diagnostics/logs.h" namespace kphp::diagnostics { @@ -34,39 +32,41 @@ concept tag_range = std::ranges::range && std::is_constructible_v; + using serialize_buffer = kphp::stl::vector; private: - std::optional buffer; + serialize_buffer buffer; k2::MonitoringSystem ms; explicit metric(k2::MonitoringSystem ms) noexcept - : buffer{bytes_vector{}}, + : buffer{serialize_buffer{}}, ms{ms} {} - metric(bytes_vector&& buffer, k2::MonitoringSystem ms) noexcept + metric(serialize_buffer&& buffer, k2::MonitoringSystem ms) noexcept : buffer{std::move(buffer)}, - ms{ms} {} + ms{ms} { + this->buffer.clear(); + } template requires std::is_arithmetic_v - static void store_number(bytes_vector& buf, const T& number) noexcept { + static void store_number(serialize_buffer& buf, const T& number) noexcept { const auto* src{static_cast(static_cast(std::addressof(number)))}; buf.insert(buf.end(), src, src + sizeof(T)); } - static void store_string(bytes_vector& buf, const std::string_view& string) noexcept { + static void store_string(serialize_buffer& buf, const std::string_view& string) noexcept { metric::store_number(buf, string.size()); buf.append_range(std::as_bytes(std::span{string.data(), string.size()})); } - static void store_tag(bytes_vector& buf, std::string_view tag_name, std::string_view tag_value) noexcept { + static void store_tag(serialize_buffer& buf, std::string_view tag_name, std::string_view tag_value) noexcept { metric::store_string(buf, tag_name); metric::store_string(buf, tag_value); } template - static void store_msg(bytes_vector& buf, std::string_view metric_name, size_t msg_len, TagRange&& tags) noexcept { + static void store_msg(serialize_buffer& buf, std::string_view metric_name, size_t msg_len, TagRange&& tags) noexcept { metric::store_number(buf, msg_len); metric::store_string(buf, metric_name); for (const auto& [tag_name, tag_value] : std::forward(tags)) { @@ -92,92 +92,84 @@ struct metric final { return metric{ms}; } - static metric with_buffer(bytes_vector& buffer, k2::MonitoringSystem ms) noexcept { + static metric with_buffer(serialize_buffer& buffer, k2::MonitoringSystem ms) noexcept { return metric{std::move(buffer), ms}; } - template - metric build_value(std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { - kphp::log::assertion(this->buffer.has_value()); - bytes_vector& buf{this->buffer.value()}; - + template + decltype(auto) build_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, + std::optional timestamp = std::nullopt) noexcept { size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; - buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + value_f64 + msg_len + msg + self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + + msg_len); // timestamp_u64 + value_kind_u8 + value_f64 + msg_len + msg uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - metric::store_number(buf, ns_timestamp); - metric::store_number(buf, static_cast(k2::MetricValueKind::VALUE)); - metric::store_number(buf, value); - metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); - return *this; + metric::store_number(self.buffer, ns_timestamp); + metric::store_number(self.buffer, static_cast(k2::MetricValueKind::VALUE)); + metric::store_number(self.buffer, value); + metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); + return std::forward(self); } - template - metric build_values_array(std::string_view metric_name, TagRange&& tags, std::span values, - std::optional timestamp = std::nullopt) noexcept { - kphp::log::assertion(this->buffer.has_value()); - bytes_vector& buf{this->buffer.value()}; - + template + decltype(auto) build_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, + std::optional timestamp = std::nullopt) noexcept { size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; - buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + - msg_len); // timestamp_u64 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_len + msg + self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + + msg_len); // timestamp_u64 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_len + msg uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - metric::store_number(buf, ns_timestamp); - metric::store_number(buf, static_cast(k2::MetricValueKind::VALUES_ARRAY)); - metric::store_number(buf, values.size()); + metric::store_number(self.buffer, ns_timestamp); + metric::store_number(self.buffer, static_cast(k2::MetricValueKind::VALUES_ARRAY)); + metric::store_number(self.buffer, values.size()); for (const auto& value : values) { - metric::store_number(buf, value); + metric::store_number(self.buffer, value); } - metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); - return *this; + metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); + return std::forward(self); } - template - metric build_count(std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { - kphp::log::assertion(this->buffer.has_value()); - bytes_vector& buf{this->buffer.value()}; - + template + decltype(auto) build_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, + std::optional timestamp = std::nullopt) noexcept { size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; - buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + count_u32 + msg_len + msg + self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + + msg_len); // timestamp_u64 + value_kind_u8 + count_u32 + msg_len + msg uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - metric::store_number(buf, ns_timestamp); - metric::store_number(buf, static_cast(k2::MetricValueKind::COUNT)); - metric::store_number(buf, count); - metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); + metric::store_number(self.buffer, ns_timestamp); + metric::store_number(self.buffer, static_cast(k2::MetricValueKind::COUNT)); + metric::store_number(self.buffer, count); + metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); - return *this; + return std::forward(self); } - template - metric build_increment(std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { - kphp::log::assertion(this->buffer.has_value()); - bytes_vector& buf{this->buffer.value()}; - + template + decltype(auto) build_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; - buf.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + msg_len + msg + self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + msg_len + msg uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - metric::store_number(buf, ns_timestamp); - metric::store_number(buf, static_cast(k2::MetricValueKind::INC)); - metric::store_msg(buf, metric_name, msg_len, std::forward(tags)); - return *this; + metric::store_number(self.buffer, ns_timestamp); + metric::store_number(self.buffer, static_cast(k2::MetricValueKind::INC)); + metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); + return std::forward(self); } std::expected send() const noexcept { - kphp::log::assertion(this->buffer.has_value()); - return k2::write_metric(this->buffer.value(), this->ms); + return k2::write_metric(this->buffer, this->ms); } - std::expected send() && noexcept { - kphp::log::assertion(this->buffer.has_value()); - bytes_vector& buf{this->buffer.value()}; - return k2::write_metric(buf, this->ms).transform([&buf]() noexcept { return std::move(buf); }); + std::expected send() && noexcept { + return k2::write_metric(this->buffer, this->ms).transform([this]() noexcept { + this->buffer.clear(); + return std::move(this->buffer); + }); } }; From 6c9137b6f300fcbe0568bafb3ebe4f03c433cabe Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 18:13:23 +0300 Subject: [PATCH 22/48] minor fix --- runtime-light/stdlib/diagnostics/metrics.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 80f3c7950c..af1f1d70ae 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -44,9 +44,7 @@ struct metric final { metric(serialize_buffer&& buffer, k2::MonitoringSystem ms) noexcept : buffer{std::move(buffer)}, - ms{ms} { - this->buffer.clear(); - } + ms{ms} {} template requires std::is_arithmetic_v @@ -92,13 +90,14 @@ struct metric final { return metric{ms}; } - static metric with_buffer(serialize_buffer& buffer, k2::MonitoringSystem ms) noexcept { + static metric with_buffer(serialize_buffer&& buffer, k2::MonitoringSystem ms) noexcept { return metric{std::move(buffer), ms}; } template decltype(auto) build_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { + self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + value_f64 + msg_len + msg @@ -115,6 +114,7 @@ struct metric final { template decltype(auto) build_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, std::optional timestamp = std::nullopt) noexcept { + self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_len + msg @@ -134,6 +134,7 @@ struct metric final { template decltype(auto) build_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { + self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + count_u32 + msg_len + msg @@ -150,6 +151,7 @@ struct metric final { template decltype(auto) build_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { + self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + msg_len + msg From 9c6391242477959538c8550ffe190ecdf39c57ca Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 18:18:00 +0300 Subject: [PATCH 23/48] minor fix --- runtime-light/stdlib/diagnostics/metrics.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index af1f1d70ae..8ba42a48dc 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -44,7 +44,9 @@ struct metric final { metric(serialize_buffer&& buffer, k2::MonitoringSystem ms) noexcept : buffer{std::move(buffer)}, - ms{ms} {} + ms{ms} { + this->buffer.clear(); + } template requires std::is_arithmetic_v @@ -97,7 +99,6 @@ struct metric final { template decltype(auto) build_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { - self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + value_f64 + msg_len + msg @@ -114,7 +115,6 @@ struct metric final { template decltype(auto) build_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, std::optional timestamp = std::nullopt) noexcept { - self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_len + msg @@ -134,7 +134,6 @@ struct metric final { template decltype(auto) build_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { - self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + count_u32 + msg_len + msg @@ -151,7 +150,6 @@ struct metric final { template decltype(auto) build_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { - self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + msg_len + msg From 713b47ae0490b5f3806f4b303011d782353d1b34 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 18:32:58 +0300 Subject: [PATCH 24/48] returned buffer.clear() --- runtime-light/stdlib/diagnostics/metrics.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 8ba42a48dc..af1f1d70ae 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -44,9 +44,7 @@ struct metric final { metric(serialize_buffer&& buffer, k2::MonitoringSystem ms) noexcept : buffer{std::move(buffer)}, - ms{ms} { - this->buffer.clear(); - } + ms{ms} {} template requires std::is_arithmetic_v @@ -99,6 +97,7 @@ struct metric final { template decltype(auto) build_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { + self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + value_f64 + msg_len + msg @@ -115,6 +114,7 @@ struct metric final { template decltype(auto) build_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, std::optional timestamp = std::nullopt) noexcept { + self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_len + msg @@ -134,6 +134,7 @@ struct metric final { template decltype(auto) build_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { + self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + count_u32 + msg_len + msg @@ -150,6 +151,7 @@ struct metric final { template decltype(auto) build_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { + self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + msg_len + msg From a7e392fe8c74db6985617f0c43db7f2eb6bc594a Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 18:46:32 +0300 Subject: [PATCH 25/48] fix --- runtime-light/k2-platform/k2-api.h | 4 +- runtime-light/k2-platform/k2-header.h | 10 ++-- runtime-light/stdlib/diagnostics/metrics.h | 60 +++++++++++----------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 1480d15576..3124e69415 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -249,8 +249,8 @@ inline std::expected madvise(void* addr, size_t length, int32_t a return {}; } -inline std::expected write_metric(std::span serialized_metric, k2::MonitoringSystem ms) noexcept { - if (auto error_code{k2_write_metric(serialized_metric.data(), serialized_metric.size(), ms)}; error_code != k2::errno_ok) [[unlikely]] { +inline std::expected write_metrics(std::span serialized_metric, k2::MonitoringSystem ms) noexcept { + if (auto error_code{k2_write_metrics(serialized_metric.data(), serialized_metric.size(), ms)}; error_code != k2::errno_ok) [[unlikely]] { return std::unexpected{error_code}; } return {}; diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index 6c7347aa8a..bb592d2fa9 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -403,16 +403,16 @@ 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 + * Writes a pre-serialized metrics to the specified monitoring system. + * The buffer must contain a metrics serialized according to the format described above * (see `MetricValueKind` 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 `buf` A pointer to the serialized metrics data. + * @param `buf_len` The length of the serialized metrics data in bytes. * @param `ms` The target monitoring system. * @return returns 0 if everything is fine, otherwise error code */ -int32_t k2_write_metric(const void* buf, size_t buf_len, enum MonitoringSystem ms); +int32_t k2_write_metrics(const void* buf, size_t buf_len, enum MonitoringSystem ms); /** * Sets `StreamStatus.please_whutdown_write=true` for the component on the diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index af1f1d70ae..e32a5da848 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -85,6 +85,17 @@ struct metric final { return result; } + std::expected send() const noexcept { + return k2::write_metrics(this->buffer, this->ms); + } + + std::expected send() && noexcept { + return k2::write_metrics(this->buffer, this->ms).transform([this]() noexcept { + this->buffer.clear(); + return std::move(this->buffer); + }); + } + public: static metric empty(k2::MonitoringSystem ms) noexcept { return metric{ms}; @@ -95,8 +106,8 @@ struct metric final { } template - decltype(auto) build_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, - std::optional timestamp = std::nullopt) noexcept { + decltype(auto) send_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, + std::optional timestamp = std::nullopt) noexcept { self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + @@ -108,12 +119,12 @@ struct metric final { metric::store_number(self.buffer, static_cast(k2::MetricValueKind::VALUE)); metric::store_number(self.buffer, value); metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); - return std::forward(self); + return std::forward(self).send(); } template - decltype(auto) build_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, - std::optional timestamp = std::nullopt) noexcept { + decltype(auto) send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, + std::optional timestamp = std::nullopt) noexcept { self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + @@ -128,12 +139,12 @@ struct metric final { metric::store_number(self.buffer, value); } metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); - return std::forward(self); + return std::forward(self).send(); } template - decltype(auto) build_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, - std::optional timestamp = std::nullopt) noexcept { + decltype(auto) send_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, + std::optional timestamp = std::nullopt) noexcept { self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + @@ -146,11 +157,11 @@ struct metric final { metric::store_number(self.buffer, count); metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); - return std::forward(self); + return std::forward(self).send(); } template - decltype(auto) build_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { + decltype(auto) send_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { self.buffer.clear(); size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + msg_len + msg @@ -160,18 +171,7 @@ struct metric final { metric::store_number(self.buffer, ns_timestamp); metric::store_number(self.buffer, static_cast(k2::MetricValueKind::INC)); metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); - return std::forward(self); - } - - std::expected send() const noexcept { - return k2::write_metric(this->buffer, this->ms); - } - - std::expected send() && noexcept { - return k2::write_metric(this->buffer, this->ms).transform([this]() noexcept { - this->buffer.clear(); - return std::move(this->buffer); - }); + return std::forward(self).send(); } }; @@ -199,20 +199,20 @@ struct metric_builder final { return *this; } - kphp::diagnostics::metric build_value(double value, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).build_value(this->metric_name, this->tags, value, timestamp); + decltype(auto) send_value(double value, std::optional timestamp = std::nullopt) const noexcept { + return metric::empty(this->ms).send_value(this->metric_name, this->tags, value, timestamp); } - kphp::diagnostics::metric build_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).build_values_array(this->metric_name, this->tags, values, timestamp); + decltype(auto) send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { + return metric::empty(this->ms).send_values_array(this->metric_name, this->tags, values, timestamp); } - kphp::diagnostics::metric build_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).build_count(this->metric_name, this->tags, count, timestamp); + decltype(auto) send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { + return metric::empty(this->ms).send_count(this->metric_name, this->tags, count, timestamp); } - kphp::diagnostics::metric build_increment(std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).build_increment(this->metric_name, this->tags, timestamp); + decltype(auto) send_increment(std::optional timestamp = std::nullopt) const noexcept { + return metric::empty(this->ms).send_increment(this->metric_name, this->tags, timestamp); } }; } // namespace kphp::diagnostics From b1d7adda49d78ffd3f9ab70a417941f932e3aba3 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 19:09:50 +0300 Subject: [PATCH 26/48] added include --- runtime-light/stdlib/diagnostics/metrics.h | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index e32a5da848..3b3c16ab6f 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include From dfd5c0c129491162cf4f5219d75944d4d03f86a6 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 23 Jun 2026 19:22:59 +0300 Subject: [PATCH 27/48] chrono to k2::system_time --- runtime-light/stdlib/diagnostics/metrics.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 3b3c16ab6f..d9d7261ec1 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include #include @@ -74,7 +73,9 @@ struct metric final { } static uint64_t ns_timestamp_now() noexcept { - return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + k2::SystemTime st{}; + k2::system_time(std::addressof(st)); + return st.since_epoch_ns; } template From 9c5b54ecc4d1a848cbaf25f9ec2caedf63f5dff4 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Thu, 25 Jun 2026 19:22:04 +0300 Subject: [PATCH 28/48] format changed: my own to tl --- runtime-light/k2-platform/k2-api.h | 2 - runtime-light/k2-platform/k2-header.h | 32 ++--- runtime-light/stdlib/diagnostics/metrics.h | 153 ++++++--------------- runtime-light/tl/tl-types.h | 130 +++++++++++++++++ 4 files changed, 188 insertions(+), 129 deletions(-) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 3124e69415..4651cc8a1d 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -74,8 +74,6 @@ using UpdateStatus = UpdateStatus; using MonitoringSystem = MonitoringSystem; -using MetricValueKind = MetricValueKind; - using TimePoint = TimePoint; using SystemTime = SystemTime; diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index bb592d2fa9..f4e3cf039b 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -99,23 +99,6 @@ enum UpdateStatus { enum MonitoringSystem { StatsHouse }; -/* - * Serialized metric format: - * ... - * - * value_format: - * - single float value - * ... - array of float values - * - count value - * - counter increment - * - * msg_len: sizeof(metric_name_len) + len(metric_name) + sizeof(tag1_name_len) + len(tag1_name) + sizeof(tag1_value_len) + len(tag1_value) + ... - * - * All numeric fields are stored in native byte order - * All string length fields (*_len) are stored as size_t - */ -enum MetricValueKind : uint8_t { VALUE, VALUES_ARRAY, COUNT, INC }; - struct ImageInfo { // Base const char* image_name; @@ -404,8 +387,19 @@ int32_t k2_madvise(void* addr, size_t length, int32_t advise); /** * Writes a pre-serialized metrics to the specified monitoring system. - * The buffer must contain a metrics serialized according to the format described above - * (see `MetricValueKind` and the serialized metric format comment). + * + * The buffer must contain a metric serialized according to the following format + * (TL serialization, native byte order): + * ... + * tag := + * + * value format: + * <`VALUE_MAGIC`:u32> - single double value + * <`VALUES_ARRAY_MAGIC`:u32>... - array of double values + * <`COUNT_MAGIC`:u32> - count value + * <`INC_MAGIC`:u32> - counter increment + * + * tl string is the standard TL string encoding. * * @param `buf` A pointer to the serialized metrics data. * @param `buf_len` The length of the serialized metrics data in bytes. diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index d9d7261ec1..97c5252139 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -18,60 +18,26 @@ #include "runtime-common/core/allocator/script-allocator.h" #include "runtime-common/core/std/containers.h" #include "runtime-light/k2-platform/k2-api.h" - -namespace kphp::diagnostics { - -namespace details { -inline size_t string_sizeof(const std::string_view& string) noexcept { - return sizeof(size_t) + string.size(); -} -} // namespace details +#include "runtime-light/tl/tl-core.h" +#include "runtime-light/tl/tl-types.h" template concept tag_range = std::ranges::range && std::is_constructible_v, std::ranges::range_value_t>; +namespace kphp::diagnostics { struct metric final { -public: - using serialize_buffer = kphp::stl::vector; - private: - serialize_buffer buffer; + tl::storer tls; k2::MonitoringSystem ms; explicit metric(k2::MonitoringSystem ms) noexcept - : buffer{serialize_buffer{}}, + : tls{0}, ms{ms} {} - metric(serialize_buffer&& buffer, k2::MonitoringSystem ms) noexcept - : buffer{std::move(buffer)}, + metric(tl::storer&& tls, k2::MonitoringSystem ms) noexcept + : tls{std::move(tls)}, ms{ms} {} - template - requires std::is_arithmetic_v - static void store_number(serialize_buffer& buf, const T& number) noexcept { - const auto* src{static_cast(static_cast(std::addressof(number)))}; - buf.insert(buf.end(), src, src + sizeof(T)); - } - - static void store_string(serialize_buffer& buf, const std::string_view& string) noexcept { - metric::store_number(buf, string.size()); - buf.append_range(std::as_bytes(std::span{string.data(), string.size()})); - } - - static void store_tag(serialize_buffer& buf, std::string_view tag_name, std::string_view tag_value) noexcept { - metric::store_string(buf, tag_name); - metric::store_string(buf, tag_value); - } - - template - static void store_msg(serialize_buffer& buf, std::string_view metric_name, size_t msg_len, TagRange&& tags) noexcept { - metric::store_number(buf, msg_len); - metric::store_string(buf, metric_name); - for (const auto& [tag_name, tag_value] : std::forward(tags)) { - metric::store_tag(buf, std::string_view{tag_name}, std::string_view{tag_value}); - } - } - static uint64_t ns_timestamp_now() noexcept { k2::SystemTime st{}; k2::system_time(std::addressof(st)); @@ -79,101 +45,72 @@ struct metric final { } template - static size_t calc_msg_len(std::string_view metric_name, TagRange&& tags) noexcept { - size_t result{kphp::diagnostics::details::string_sizeof(metric_name)}; - for (const auto& [tag_name, tag_value] : std::forward(tags)) { - result += kphp::diagnostics::details::string_sizeof(std::string_view{tag_name}) + kphp::diagnostics::details::string_sizeof(std::string_view{tag_value}); - } - return result; + static auto get_sv_range(TagRange&& tags) noexcept { + return tags | std::views::transform([](const auto& elem) noexcept -> tl::pair { + tl::string first{.value = elem.first}; + tl::string second{.value = elem.second}; + return tl::pair{.pair = std::pair{first, second}}; + }); } std::expected send() const noexcept { - return k2::write_metrics(this->buffer, this->ms); + return k2::write_metrics(this->tls.view(), this->ms); } - std::expected send() && noexcept { - return k2::write_metrics(this->buffer, this->ms).transform([this]() noexcept { - this->buffer.clear(); - return std::move(this->buffer); + std::expected send() && noexcept { + return k2::write_metrics(this->tls.view(), this->ms).transform([this]() noexcept { + this->tls.clear(); + return std::move(this->tls); }); } + template + decltype(auto) build_and_send(this Self&& self, std::string_view metric_name, TagRange&& tags, tl::metricValueFormat value, + std::optional timestamp) noexcept { + self.tls.clear(); + + uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; + tl::metric metric{ + .timestamp = tl::u64{ns_timestamp}, .value = value, .metric_name = tl::string{metric_name}, .tags = get_sv_range(std::forward(tags))}; + + self.tls.reserve(metric.footprint()); + metric.store(self.tls); + + return std::forward(self).send(); + } + public: static metric empty(k2::MonitoringSystem ms) noexcept { return metric{ms}; } - static metric with_buffer(serialize_buffer&& buffer, k2::MonitoringSystem ms) noexcept { - return metric{std::move(buffer), ms}; + static metric with_buffer(tl::storer&& tls, k2::MonitoringSystem ms) noexcept { + return metric{std::move(tls), ms}; } template decltype(auto) send_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { - self.buffer.clear(); - size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; - self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) + - msg_len); // timestamp_u64 + value_kind_u8 + value_f64 + msg_len + msg - - uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - - metric::store_number(self.buffer, ns_timestamp); - metric::store_number(self.buffer, static_cast(k2::MetricValueKind::VALUE)); - metric::store_number(self.buffer, value); - metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); - return std::forward(self).send(); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat{tl::MetricValue{tl::f64{value}}}, + timestamp); } template decltype(auto) send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, std::optional timestamp = std::nullopt) noexcept { - self.buffer.clear(); - size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; - self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) + - msg_len); // timestamp_u64 + value_kind_u8 + array_len_usize + value_f64*array_len + msg_len + msg - - uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - - metric::store_number(self.buffer, ns_timestamp); - metric::store_number(self.buffer, static_cast(k2::MetricValueKind::VALUES_ARRAY)); - metric::store_number(self.buffer, values.size()); - for (const auto& value : values) { - metric::store_number(self.buffer, value); - } - metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); - return std::forward(self).send(); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat{tl::MetricValuesArray{values}}, timestamp); } template decltype(auto) send_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { - self.buffer.clear(); - size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; - self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(size_t) + - msg_len); // timestamp_u64 + value_kind_u8 + count_u32 + msg_len + msg - - uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - - metric::store_number(self.buffer, ns_timestamp); - metric::store_number(self.buffer, static_cast(k2::MetricValueKind::COUNT)); - metric::store_number(self.buffer, count); - metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); - - return std::forward(self).send(); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat{tl::MetricCount{tl::u32{count}}}, + timestamp); } template decltype(auto) send_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { - self.buffer.clear(); - size_t msg_len{metric::calc_msg_len(metric_name, std::forward(tags))}; - self.buffer.reserve(sizeof(uint64_t) + sizeof(uint8_t) + sizeof(size_t) + msg_len); // timestamp_u64 + value_kind_u8 + msg_len + msg - - uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - - metric::store_number(self.buffer, ns_timestamp); - metric::store_number(self.buffer, static_cast(k2::MetricValueKind::INC)); - metric::store_msg(self.buffer, metric_name, msg_len, std::forward(tags)); - return std::forward(self).send(); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat{tl::MetricInc{}}, timestamp); } }; @@ -201,19 +138,19 @@ struct metric_builder final { return *this; } - decltype(auto) send_value(double value, std::optional timestamp = std::nullopt) const noexcept { + auto send_value(double value, std::optional timestamp = std::nullopt) const noexcept { return metric::empty(this->ms).send_value(this->metric_name, this->tags, value, timestamp); } - decltype(auto) send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { + auto send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { return metric::empty(this->ms).send_values_array(this->metric_name, this->tags, values, timestamp); } - decltype(auto) send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { + auto send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { return metric::empty(this->ms).send_count(this->metric_name, this->tags, count, timestamp); } - decltype(auto) send_increment(std::optional timestamp = std::nullopt) const noexcept { + auto send_increment(std::optional timestamp = std::nullopt) const noexcept { return metric::empty(this->ms).send_increment(this->metric_name, this->tags, timestamp); } }; diff --git a/runtime-light/tl/tl-types.h b/runtime-light/tl/tl-types.h index f3dadda7e6..f04e06a971 100644 --- a/runtime-light/tl/tl-types.h +++ b/runtime-light/tl/tl-types.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -478,6 +479,30 @@ struct vector final { } }; +template +struct pair final { + std::pair pair; + + bool fetch(tl::fetcher& tlf) noexcept + requires tl::deserializable && tl::deserializable + { + return pair.first.fetch(tlf) && pair.second.fetch(tlf); + } + + void store(tl::storer& tls) const noexcept + requires tl::serializable && tl::serializable + { + pair.first.store(tls); + pair.second.store(tls); + } + + constexpr size_t footprint() const noexcept + requires tl::footprintable && tl::footprintable + { + return pair.first.footprint() + pair.second.footprint(); + } +}; + template struct Vector final { tl::vector inner{}; @@ -1686,6 +1711,111 @@ class CompositeWebTransferWaitUpdatesResultOk final { } }; +// ===== METRICS ===== + +class MetricValue final { + static constexpr uint32_t MAGIC = 0xcb5eb87U; + +public: + tl::f64 value{}; + + void store(::tl::storer& tls) const noexcept { + tl::magic{.value = MetricValue::MAGIC}.store(tls); + value.store(tls); + } + + constexpr size_t footprint() const noexcept { + return tl::magic{.value = MetricValue::MAGIC}.footprint() + value.footprint(); + } +}; + +class MetricValuesArray final { + static constexpr uint32_t MAGIC = 0xd4a59582U; + +public: + std::span values; + + void store(::tl::storer& tls) const noexcept { + tl::magic{.value = MetricValuesArray::MAGIC}.store(tls); + tl::u32{.value = static_cast(values.size())}.store(tls); + std::ranges::for_each(values, [&tls](double value) noexcept { tl::f64{.value = value}.store(tls); }); + } + + constexpr size_t footprint() const noexcept { + return tl::magic{.value = MetricValuesArray::MAGIC}.footprint() + tl::u32{.value = static_cast(values.size())}.footprint() + + values.size() * tl::f64{}.footprint(); + } +}; + +class MetricCount final { + static constexpr uint32_t MAGIC = 0x941bf7d1U; + +public: + tl::u32 count{}; + + void store(::tl::storer& tls) const noexcept { + tl::magic{.value = MetricCount::MAGIC}.store(tls); + count.store(tls); + } + + constexpr size_t footprint() const noexcept { + return tl::magic{.value = MetricCount::MAGIC}.footprint() + count.footprint(); + } +}; + +class MetricInc final { + static constexpr uint32_t MAGIC = 0x23e305abU; + +public: + void store(::tl::storer& tls) const noexcept { + tl::magic{.value = MetricInc::MAGIC}.store(tls); + } + + constexpr size_t footprint() const noexcept { + return tl::magic{.value = MetricInc::MAGIC}.footprint(); + } +}; + +struct metricValueFormat final { + std::variant value; + void store(::tl::storer& tls) const noexcept { + std::visit([&tls](const auto& v) noexcept { v.store(tls); }, value); + } + + constexpr size_t footprint() const noexcept { + return std::visit([](const auto& v) noexcept { return v.footprint(); }, value); + } +}; + +template +struct metric final { + using TagType = std::ranges::range_value_t; + + tl::u64 timestamp{}; + tl::metricValueFormat value{}; + tl::string metric_name{}; + Range tags; + + void store(tl::storer& tls) const noexcept + requires tl::serializable + { + timestamp.store(tls); + value.store(tls); + metric_name.store(tls); + + tl::u32{.value = static_cast(std::ranges::distance(tags))}.store(tls); + std::for_each(tags.begin(), tags.end(), [&tls](const auto& elem) noexcept { elem.store(tls); }); + } + + constexpr size_t footprint() const noexcept + requires tl::footprintable + { + return timestamp.footprint() + value.footprint() + metric_name.footprint() + + tl::u32{.value = static_cast(std::ranges::distance(tags))}.footprint() + + std::accumulate(tags.begin(), tags.end(), size_t{0}, [](size_t acc, const auto& elem) noexcept { return acc + elem.footprint(); }); + } +}; + } // namespace tl namespace tl2 { From 476e9cfe00e8f6fbeaf8083d124492f55ee8ff78 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 26 Jun 2026 10:18:23 +0300 Subject: [PATCH 29/48] fixes --- runtime-light/stdlib/diagnostics/metrics.h | 43 ++++++------ runtime-light/tl/tl-types.h | 77 +++++++++++++--------- 2 files changed, 69 insertions(+), 51 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 97c5252139..d4bd882132 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -44,19 +44,11 @@ struct metric final { return st.since_epoch_ns; } - template - static auto get_sv_range(TagRange&& tags) noexcept { - return tags | std::views::transform([](const auto& elem) noexcept -> tl::pair { - tl::string first{.value = elem.first}; - tl::string second{.value = elem.second}; - return tl::pair{.pair = std::pair{first, second}}; - }); - } - std::expected send() const noexcept { return k2::write_metrics(this->tls.view(), this->ms); } + // сlears buffer and returns it with preserved capacity for reuse by metric::with_buffer() std::expected send() && noexcept { return k2::write_metrics(this->tls.view(), this->ms).transform([this]() noexcept { this->tls.clear(); @@ -64,14 +56,20 @@ struct metric final { }); } - template - decltype(auto) build_and_send(this Self&& self, std::string_view metric_name, TagRange&& tags, tl::metricValueFormat value, + template + decltype(auto) build_and_send(this Self&& self, std::string_view metric_name, TagRange&& tags, tl::metricValueFormat value, std::optional timestamp) noexcept { self.tls.clear(); uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - tl::metric metric{ - .timestamp = tl::u64{ns_timestamp}, .value = value, .metric_name = tl::string{metric_name}, .tags = get_sv_range(std::forward(tags))}; + tl::metric metric{.timestamp = tl::u64{ns_timestamp}, + .value = value, + .metric_name = tl::string{metric_name}, + .tags = std::forward(tags) | std::views::transform([](const auto& elem) noexcept -> tl::pair { + tl::string first{elem.first}; + tl::string second{elem.second}; + return tl::pair{.value = std::pair{first, second}}; + })}; self.tls.reserve(metric.footprint()); metric.store(self.tls); @@ -91,26 +89,30 @@ struct metric final { template decltype(auto) send_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat{tl::MetricValue{tl::f64{value}}}, + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat<>{tl::MetricValue{tl::f64{value}}}, timestamp); } - template - decltype(auto) send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, + template + requires std::same_as>, tl::f64> + decltype(auto) send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, ValueRange&& values, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat{tl::MetricValuesArray{values}}, timestamp); + using range_t = std::remove_cvref_t; + return std::forward(self).build_and_send(metric_name, std::forward(tags), + tl::metricValueFormat{tl::MetricValuesArray{.values = std::forward(values)}}, + timestamp); } template decltype(auto) send_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat{tl::MetricCount{tl::u32{count}}}, + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat<>{tl::MetricCount{tl::u32{count}}}, timestamp); } template decltype(auto) send_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat{tl::MetricInc{}}, timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat<>{tl::MetricInc{}}, timestamp); } }; @@ -143,7 +145,8 @@ struct metric_builder final { } auto send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_values_array(this->metric_name, this->tags, values, timestamp); + return metric::empty(this->ms).send_values_array(this->metric_name, this->tags, + values | std::views::transform([](const double& value) noexcept { return tl::f64{value}; }), timestamp); } auto send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { diff --git a/runtime-light/tl/tl-types.h b/runtime-light/tl/tl-types.h index f04e06a971..66b8cca89c 100644 --- a/runtime-light/tl/tl-types.h +++ b/runtime-light/tl/tl-types.h @@ -481,25 +481,25 @@ struct vector final { template struct pair final { - std::pair pair; + std::pair value; bool fetch(tl::fetcher& tlf) noexcept requires tl::deserializable && tl::deserializable { - return pair.first.fetch(tlf) && pair.second.fetch(tlf); + return value.first.fetch(tlf) && value.second.fetch(tlf); } void store(tl::storer& tls) const noexcept requires tl::serializable && tl::serializable { - pair.first.store(tls); - pair.second.store(tls); + value.first.store(tls); + value.second.store(tls); } constexpr size_t footprint() const noexcept requires tl::footprintable && tl::footprintable { - return pair.first.footprint() + pair.second.footprint(); + return value.first.footprint() + value.second.footprint(); } }; @@ -1719,7 +1719,7 @@ class MetricValue final { public: tl::f64 value{}; - void store(::tl::storer& tls) const noexcept { + void store(tl::storer& tls) const noexcept { tl::magic{.value = MetricValue::MAGIC}.store(tls); value.store(tls); } @@ -1729,21 +1729,40 @@ class MetricValue final { } }; -class MetricValuesArray final { +template +class MetricValuesArray; + +template +requires std::same_as>, tl::f64> +class MetricValuesArray final { static constexpr uint32_t MAGIC = 0xd4a59582U; + size_t size() const noexcept { + return std::ranges::distance(values); + } + public: - std::span values; + Range values; - void store(::tl::storer& tls) const noexcept { + void store(tl::storer& tls) const noexcept { tl::magic{.value = MetricValuesArray::MAGIC}.store(tls); - tl::u32{.value = static_cast(values.size())}.store(tls); - std::ranges::for_each(values, [&tls](double value) noexcept { tl::f64{.value = value}.store(tls); }); + tl::u32{.value = static_cast(this->size())}.store(tls); + std::ranges::for_each(values, [&tls](const tl::f64& v) noexcept { v.store(tls); }); + } + + constexpr size_t footprint() const noexcept { + auto size{this->size()}; + return tl::magic{.value = MetricValuesArray::MAGIC}.footprint() + tl::u32{.value = static_cast(size)}.footprint() + size * tl::f64{}.footprint(); } +}; + +template<> +class MetricValuesArray { +public: + void store(tl::storer& /*unused*/) const noexcept {} constexpr size_t footprint() const noexcept { - return tl::magic{.value = MetricValuesArray::MAGIC}.footprint() + tl::u32{.value = static_cast(values.size())}.footprint() + - values.size() * tl::f64{}.footprint(); + return 0; } }; @@ -1753,7 +1772,7 @@ class MetricCount final { public: tl::u32 count{}; - void store(::tl::storer& tls) const noexcept { + void store(tl::storer& tls) const noexcept { tl::magic{.value = MetricCount::MAGIC}.store(tls); count.store(tls); } @@ -1767,7 +1786,7 @@ class MetricInc final { static constexpr uint32_t MAGIC = 0x23e305abU; public: - void store(::tl::storer& tls) const noexcept { + void store(tl::storer& tls) const noexcept { tl::magic{.value = MetricInc::MAGIC}.store(tls); } @@ -1776,9 +1795,10 @@ class MetricInc final { } }; +template struct metricValueFormat final { - std::variant value; - void store(::tl::storer& tls) const noexcept { + std::variant, MetricCount, MetricInc> value; + void store(tl::storer& tls) const noexcept { std::visit([&tls](const auto& v) noexcept { v.store(tls); }, value); } @@ -1787,32 +1807,27 @@ struct metricValueFormat final { } }; -template +template +requires std::same_as>, tl::pair> struct metric final { - using TagType = std::ranges::range_value_t; - tl::u64 timestamp{}; - tl::metricValueFormat value{}; + tl::metricValueFormat value{}; tl::string metric_name{}; - Range tags; + TagRange tags; - void store(tl::storer& tls) const noexcept - requires tl::serializable - { + void store(tl::storer& tls) const noexcept { timestamp.store(tls); value.store(tls); metric_name.store(tls); tl::u32{.value = static_cast(std::ranges::distance(tags))}.store(tls); - std::for_each(tags.begin(), tags.end(), [&tls](const auto& elem) noexcept { elem.store(tls); }); + std::ranges::for_each(tags, [&tls](const auto& elem) noexcept { elem.store(tls); }); } - constexpr size_t footprint() const noexcept - requires tl::footprintable - { + constexpr size_t footprint() const noexcept { return timestamp.footprint() + value.footprint() + metric_name.footprint() + - tl::u32{.value = static_cast(std::ranges::distance(tags))}.footprint() + - std::accumulate(tags.begin(), tags.end(), size_t{0}, [](size_t acc, const auto& elem) noexcept { return acc + elem.footprint(); }); + std::ranges::fold_left(tags, tl::u32{.value = static_cast(std::ranges::distance(tags))}.footprint(), + [](size_t acc, const auto& elem) noexcept { return acc + elem.footprint(); }); } }; From 9e23659caf71db14b2a6e0f37516e29b7526bfc6 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 26 Jun 2026 10:45:20 +0300 Subject: [PATCH 30/48] fixes --- runtime-light/stdlib/diagnostics/metrics.h | 25 +++++++++++++--------- runtime-light/tl/tl-types.h | 10 ++++----- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index d4bd882132..b93f112b07 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -21,10 +21,10 @@ #include "runtime-light/tl/tl-core.h" #include "runtime-light/tl/tl-types.h" +namespace kphp::diagnostics { template concept tag_range = std::ranges::range && std::is_constructible_v, std::ranges::range_value_t>; -namespace kphp::diagnostics { struct metric final { private: tl::storer tls; @@ -48,7 +48,7 @@ struct metric final { return k2::write_metrics(this->tls.view(), this->ms); } - // сlears buffer and returns it with preserved capacity for reuse by metric::with_buffer() + // clears buffer and returns it with preserved capacity for reuse by metric::with_buffer() std::expected send() && noexcept { return k2::write_metrics(this->tls.view(), this->ms).transform([this]() noexcept { this->tls.clear(); @@ -66,9 +66,8 @@ struct metric final { .value = value, .metric_name = tl::string{metric_name}, .tags = std::forward(tags) | std::views::transform([](const auto& elem) noexcept -> tl::pair { - tl::string first{elem.first}; - tl::string second{elem.second}; - return tl::pair{.value = std::pair{first, second}}; + std::pair sv_pair{elem}; + return tl::pair{std::pair{tl::string{sv_pair.first}, tl::string{sv_pair.second}}}; })}; self.tls.reserve(metric.footprint()); @@ -130,6 +129,10 @@ struct metric_builder final { : metric_name{metric_name}, ms{ms} {} + static auto discard_buffer() noexcept { + return [](const auto&) noexcept {}; + } + public: static metric_builder metric(std::string_view metric_name, k2::MonitoringSystem ms) noexcept { return metric_builder{metric_name, ms}; @@ -141,20 +144,22 @@ struct metric_builder final { } auto send_value(double value, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_value(this->metric_name, this->tags, value, timestamp); + return metric::empty(this->ms).send_value(this->metric_name, this->tags, value, timestamp).transform(discard_buffer()); } auto send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_values_array(this->metric_name, this->tags, - values | std::views::transform([](const double& value) noexcept { return tl::f64{value}; }), timestamp); + return metric::empty(this->ms) + .send_values_array(this->metric_name, this->tags, values | std::views::transform([](const double& value) noexcept { return tl::f64{value}; }), + timestamp) + .transform(discard_buffer()); } auto send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_count(this->metric_name, this->tags, count, timestamp); + return metric::empty(this->ms).send_count(this->metric_name, this->tags, count, timestamp).transform(discard_buffer()); } auto send_increment(std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_increment(this->metric_name, this->tags, timestamp); + return metric::empty(this->ms).send_increment(this->metric_name, this->tags, timestamp).transform(discard_buffer()); } }; } // namespace kphp::diagnostics diff --git a/runtime-light/tl/tl-types.h b/runtime-light/tl/tl-types.h index 66b8cca89c..f082b891f7 100644 --- a/runtime-light/tl/tl-types.h +++ b/runtime-light/tl/tl-types.h @@ -1717,7 +1717,7 @@ class MetricValue final { static constexpr uint32_t MAGIC = 0xcb5eb87U; public: - tl::f64 value{}; + tl::f64 value; void store(tl::storer& tls) const noexcept { tl::magic{.value = MetricValue::MAGIC}.store(tls); @@ -1770,7 +1770,7 @@ class MetricCount final { static constexpr uint32_t MAGIC = 0x941bf7d1U; public: - tl::u32 count{}; + tl::u32 count; void store(tl::storer& tls) const noexcept { tl::magic{.value = MetricCount::MAGIC}.store(tls); @@ -1810,9 +1810,9 @@ struct metricValueFormat final { template requires std::same_as>, tl::pair> struct metric final { - tl::u64 timestamp{}; - tl::metricValueFormat value{}; - tl::string metric_name{}; + tl::u64 timestamp; + tl::metricValueFormat value; + tl::string metric_name; TagRange tags; void store(tl::storer& tls) const noexcept { From 3366cb67260222f4e08d57c08d21f6f3439386bb Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 26 Jun 2026 10:51:18 +0300 Subject: [PATCH 31/48] minor rename --- runtime-light/stdlib/diagnostics/metrics.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index b93f112b07..91f721454e 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -62,16 +62,16 @@ struct metric final { self.tls.clear(); uint64_t ns_timestamp{timestamp.value_or(metric::ns_timestamp_now())}; - tl::metric metric{.timestamp = tl::u64{ns_timestamp}, - .value = value, - .metric_name = tl::string{metric_name}, - .tags = std::forward(tags) | std::views::transform([](const auto& elem) noexcept -> tl::pair { - std::pair sv_pair{elem}; - return tl::pair{std::pair{tl::string{sv_pair.first}, tl::string{sv_pair.second}}}; - })}; - - self.tls.reserve(metric.footprint()); - metric.store(self.tls); + tl::metric serialized{.timestamp = tl::u64{ns_timestamp}, + .value = value, + .metric_name = tl::string{metric_name}, + .tags = std::forward(tags) | std::views::transform([](const auto& elem) noexcept -> tl::pair { + std::pair sv_pair{elem}; + return tl::pair{std::pair{tl::string{sv_pair.first}, tl::string{sv_pair.second}}}; + })}; + + self.tls.reserve(serialized.footprint()); + serialized.store(self.tls); return std::forward(self).send(); } From 0ca6ecde0c71def4b52d4bf7a7c36dbb7c6d097c Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 26 Jun 2026 11:11:41 +0300 Subject: [PATCH 32/48] minor fix --- runtime-light/stdlib/diagnostics/metrics.h | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 91f721454e..7549cee5f0 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -129,10 +129,6 @@ struct metric_builder final { : metric_name{metric_name}, ms{ms} {} - static auto discard_buffer() noexcept { - return [](const auto&) noexcept {}; - } - public: static metric_builder metric(std::string_view metric_name, k2::MonitoringSystem ms) noexcept { return metric_builder{metric_name, ms}; @@ -144,22 +140,20 @@ struct metric_builder final { } auto send_value(double value, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_value(this->metric_name, this->tags, value, timestamp).transform(discard_buffer()); + return metric::empty(this->ms).send_value(this->metric_name, this->tags, value, timestamp); } auto send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms) - .send_values_array(this->metric_name, this->tags, values | std::views::transform([](const double& value) noexcept { return tl::f64{value}; }), - timestamp) - .transform(discard_buffer()); + return metric::empty(this->ms).send_values_array(this->metric_name, this->tags, + values | std::views::transform([](const double& value) noexcept { return tl::f64{value}; }), timestamp); } auto send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_count(this->metric_name, this->tags, count, timestamp).transform(discard_buffer()); + return metric::empty(this->ms).send_count(this->metric_name, this->tags, count, timestamp); } auto send_increment(std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_increment(this->metric_name, this->tags, timestamp).transform(discard_buffer()); + return metric::empty(this->ms).send_increment(this->metric_name, this->tags, timestamp); } }; } // namespace kphp::diagnostics From 3fc576a05eeaa989b3488dfeca06c534d3fe623e Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 26 Jun 2026 13:02:49 +0300 Subject: [PATCH 33/48] added tl scheme fot metric type --- runtime-light/stdlib/diagnostics/metric.tl | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 runtime-light/stdlib/diagnostics/metric.tl diff --git a/runtime-light/stdlib/diagnostics/metric.tl b/runtime-light/stdlib/diagnostics/metric.tl new file mode 100644 index 0000000000..aae93628cf --- /dev/null +++ b/runtime-light/stdlib/diagnostics/metric.tl @@ -0,0 +1,12 @@ +---types--- + +pair {X:Type} {Y:Type} a:X b:Y = Pair X Y; + +// Metric + +metricValue#cb5eb87 value:double = MetricValueFormat +metricValuesArray#d4a59582 values:%(Vector double) = MetricValueFormat +metricCount#941bf7d1 count:int = MetricValueFormat +metricInc#23e305ab = MetricValueFormat + +metric timestamp:long value:MetricValueFormat matric_name:string tags:%(Vector %(Pair string string)) = Metric From 6c6e917caf11dcdf71369abadfc41375d75ed280 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 26 Jun 2026 14:33:46 +0300 Subject: [PATCH 34/48] fix .tl --- runtime-light/stdlib/diagnostics/metric.tl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metric.tl b/runtime-light/stdlib/diagnostics/metric.tl index aae93628cf..35f9f0fc58 100644 --- a/runtime-light/stdlib/diagnostics/metric.tl +++ b/runtime-light/stdlib/diagnostics/metric.tl @@ -1,12 +1,10 @@ ---types--- -pair {X:Type} {Y:Type} a:X b:Y = Pair X Y; - // Metric -metricValue#cb5eb87 value:double = MetricValueFormat -metricValuesArray#d4a59582 values:%(Vector double) = MetricValueFormat -metricCount#941bf7d1 count:int = MetricValueFormat -metricInc#23e305ab = MetricValueFormat +metricValue#0cb5eb87 value:double = MetricValueFormat; +metricValuesArray#d4a59582 values:%(Vector double) = MetricValueFormat; +metricCount#941bf7d1 count:int = MetricValueFormat; +metricInc#23e305ab = MetricValueFormat; -metric timestamp:long value:MetricValueFormat matric_name:string tags:%(Vector %(Pair string string)) = Metric +metric timestamp:long value:MetricValueFormat matric_name:string tags:%(Vector %(Pair string string)) = Metric; From 67a07ff968182040da55a3f78dc2a5675b4a7cfd Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 10:25:57 +0300 Subject: [PATCH 35/48] added tl::span --- runtime-light/k2-platform/k2-header.h | 8 +- runtime-light/stdlib/diagnostics/metric.tl | 13 +- runtime-light/stdlib/diagnostics/metrics.h | 24 +-- runtime-light/tl/tl-types.h | 188 +++++++++++++++++---- 4 files changed, 182 insertions(+), 51 deletions(-) diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index f4e3cf039b..cdd066c837 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -401,8 +401,12 @@ int32_t k2_madvise(void* addr, size_t length, int32_t advise); * * tl string is the standard TL string encoding. * - * @param `buf` A pointer to the serialized metrics data. - * @param `buf_len` The length of the serialized metrics data in bytes. + * Multiple metrics can be sent in a single call by concatenating them sequentially: + * ... + * Each metric is serialized independently using the format described above. + * + * @param `buf` A pointer to the serialized metric(s) data. + * @param `buf_len` The length of the serialized metric(s) data in bytes. * @param `ms` The target monitoring system. * @return returns 0 if everything is fine, otherwise error code */ diff --git a/runtime-light/stdlib/diagnostics/metric.tl b/runtime-light/stdlib/diagnostics/metric.tl index 35f9f0fc58..76b3427348 100644 --- a/runtime-light/stdlib/diagnostics/metric.tl +++ b/runtime-light/stdlib/diagnostics/metric.tl @@ -1,10 +1,13 @@ ---types--- +pair {X:Type} {Y:Type} a:X b:Y = Pair X Y; +span#dad3ae87 {t:Type} count:# data:count*[t] = Span t; + // Metric -metricValue#0cb5eb87 value:double = MetricValueFormat; -metricValuesArray#d4a59582 values:%(Vector double) = MetricValueFormat; -metricCount#941bf7d1 count:int = MetricValueFormat; -metricInc#23e305ab = MetricValueFormat; +metricValue#0cb5eb87 value:double = MetricValue; +metricValuesArray#d4a59582 values:%(Span double) = MetricValue; +metricCount#941bf7d1 count:int = MetricValue; +metricInc#23e305ab = MetricValue; -metric timestamp:long value:MetricValueFormat matric_name:string tags:%(Vector %(Pair string string)) = Metric; +metric#87d62ee3 timestamp:long value:MetricValue metric_name:string tags:%(Span %(Pair string string)) = Metric; diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 7549cee5f0..26308d3931 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -56,8 +56,8 @@ struct metric final { }); } - template - decltype(auto) build_and_send(this Self&& self, std::string_view metric_name, TagRange&& tags, tl::metricValueFormat value, + template + decltype(auto) build_and_send(this Self&& self, std::string_view metric_name, TagRange&& tags, tl::anyMetricValue value, std::optional timestamp) noexcept { self.tls.clear(); @@ -88,30 +88,25 @@ struct metric final { template decltype(auto) send_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat<>{tl::MetricValue{tl::f64{value}}}, - timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::anyMetricValue{tl::MetricValue{tl::f64{value}}}, timestamp); } - template - requires std::same_as>, tl::f64> - decltype(auto) send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, ValueRange&& values, + template + decltype(auto) send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, std::optional timestamp = std::nullopt) noexcept { - using range_t = std::remove_cvref_t; return std::forward(self).build_and_send(metric_name, std::forward(tags), - tl::metricValueFormat{tl::MetricValuesArray{.values = std::forward(values)}}, - timestamp); + tl::anyMetricValue{tl::MetricValuesArray{tl::span{values}}}, timestamp); } template decltype(auto) send_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat<>{tl::MetricCount{tl::u32{count}}}, - timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::anyMetricValue{tl::MetricCount{tl::u32{count}}}, timestamp); } template decltype(auto) send_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::metricValueFormat<>{tl::MetricInc{}}, timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::anyMetricValue{tl::MetricInc{}}, timestamp); } }; @@ -144,8 +139,7 @@ struct metric_builder final { } auto send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_values_array(this->metric_name, this->tags, - values | std::views::transform([](const double& value) noexcept { return tl::f64{value}; }), timestamp); + return metric::empty(this->ms).send_values_array(this->metric_name, this->tags, values, timestamp); } auto send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { diff --git a/runtime-light/tl/tl-types.h b/runtime-light/tl/tl-types.h index f082b891f7..3e2fbd777f 100644 --- a/runtime-light/tl/tl-types.h +++ b/runtime-light/tl/tl-types.h @@ -9,7 +9,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -503,6 +505,155 @@ struct pair final { } }; +template +class span { + static constexpr bool supports_iteration = tl::deserializable && std::default_initializable; + std::span m_data; + tl::u32 m_size; + +public: + struct const_iterator { + private: + tl::fetcher tlf; + std::optional value; + + public: + using iterator_category = std::input_iterator_tag; + using value_type = const T; + using difference_type = std::ptrdiff_t; + using pointer = const T*; + using reference = const T&; + + explicit const_iterator(tl::fetcher tlf, std::optional value) noexcept + : tlf{std::move(tlf)}, + value{std::move(value)} {} + + reference operator*() const noexcept { + kphp::log::assertion(this->value.has_value()); + return this->value.value(); + } + + pointer operator->() const noexcept { + kphp::log::assertion(this->value.has_value()); + return std::addressof(this->value.value()); + } + + const_iterator& operator++() noexcept { + if (tlf.remaining() == 0) { // the end + this->value = std::nullopt; + return *this; + } + + kphp::log::assertion(this->value.has_value()); + kphp::log::assertion(this->value->fetch(this->tlf)); + return *this; + } + + const_iterator operator++(int) noexcept { // NOLINT + const_iterator tmp{*this}; + ++*this; + return tmp; + } + + // are equal if the same data and the same position, and both (or none of them) are end() (latter is checked by comparing with has_value()) + bool operator==(const const_iterator& other) const noexcept { + return this->tlf.view().data() == other.tlf.view().data() && this->tlf.pos() == other.tlf.pos() && this->value.has_value() == other.value.has_value(); + } + }; + + span() noexcept = default; + + template + requires std::constructible_from && tl::deserializable && std::default_initializable + explicit span(std::span items) noexcept + : m_data{std::as_bytes(items)}, + m_size{tl::u32{static_cast(items.size())}} { + tl::fetcher tlf{this->m_data}; + size_t count{}; + while (T{}.fetch(tlf)) { + count++; + } + + kphp::log::assertion(tlf.remaining() == 0); + kphp::log::assertion(items.size() == count); + } + + bool fetch(tl::fetcher& tlf) noexcept + requires tl::deserializable && std::default_initializable + { + // fetch data len + tl::u32 size{}; + if (!size.fetch(tlf)) { + return false; + } + + const std::byte* tlf_data{tlf.view().data()}; + size_t pos_start{tlf.pos()}; + + // skip objects + T tmp{}; + if (!std::ranges::fold_left(std::ranges::iota_view(uint32_t{0}, size.value), true, + [&tmp, &tlf](bool acc, const auto&) noexcept { return acc && tmp.fetch(tlf); })) { + return false; + } + + // write data + size_t pos_end{tlf.pos()}; + this->m_data = std::span{tlf_data + pos_start, pos_end - pos_start}; + this->m_size = size; + return true; + } + + void store(tl::storer& tls) const noexcept { + this->m_size.store(tls); + tls.store_bytes(this->m_data); + } + + constexpr size_t footprint() const noexcept { + return this->m_size.footprint() + this->m_data.size(); + } + + std::span into_bytes() const noexcept { + return this->m_data; + } + + size_t size() const noexcept { + return this->m_size.value; + } + + const_iterator begin() const noexcept + requires supports_iteration + { + return this->cbegin(); + } + + const_iterator end() const noexcept + requires supports_iteration + { + return this->cend(); + } + + const_iterator cbegin() const noexcept + requires supports_iteration + { + tl::fetcher tlf{m_data}; + if (this->m_data.empty()) [[unlikely]] { + return const_iterator{tlf, std::nullopt}; + } + T value{}; + kphp::log::assertion(value.fetch(tlf)); + return const_iterator{std::move(tlf), std::move(value)}; + } + + const_iterator cend() const noexcept + requires supports_iteration + { + tl::fetcher tlf{m_data}; + tlf.adjust(tlf.remaining()); + return const_iterator{tlf, std::nullopt}; + } +}; + template struct Vector final { tl::vector inner{}; @@ -1729,40 +1880,19 @@ class MetricValue final { } }; -template -class MetricValuesArray; - -template -requires std::same_as>, tl::f64> -class MetricValuesArray final { +class MetricValuesArray final { static constexpr uint32_t MAGIC = 0xd4a59582U; - size_t size() const noexcept { - return std::ranges::distance(values); - } - public: - Range values; + tl::span values; void store(tl::storer& tls) const noexcept { tl::magic{.value = MetricValuesArray::MAGIC}.store(tls); - tl::u32{.value = static_cast(this->size())}.store(tls); - std::ranges::for_each(values, [&tls](const tl::f64& v) noexcept { v.store(tls); }); - } - - constexpr size_t footprint() const noexcept { - auto size{this->size()}; - return tl::magic{.value = MetricValuesArray::MAGIC}.footprint() + tl::u32{.value = static_cast(size)}.footprint() + size * tl::f64{}.footprint(); + values.store(tls); } -}; - -template<> -class MetricValuesArray { -public: - void store(tl::storer& /*unused*/) const noexcept {} constexpr size_t footprint() const noexcept { - return 0; + return tl::magic{.value = MetricValuesArray::MAGIC}.footprint() + values.footprint(); } }; @@ -1795,9 +1925,9 @@ class MetricInc final { } }; -template -struct metricValueFormat final { - std::variant, MetricCount, MetricInc> value; +struct anyMetricValue final { + std::variant value; + void store(tl::storer& tls) const noexcept { std::visit([&tls](const auto& v) noexcept { v.store(tls); }, value); } @@ -1811,7 +1941,7 @@ template requires std::same_as>, tl::pair> struct metric final { tl::u64 timestamp; - tl::metricValueFormat value; + tl::anyMetricValue value; tl::string metric_name; TagRange tags; From 202accdc53b786f6f9fb8dde77675d2d23c9a7fd Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 11:41:51 +0300 Subject: [PATCH 36/48] rule of 5 for tl::span --- runtime-light/tl/tl-types.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/runtime-light/tl/tl-types.h b/runtime-light/tl/tl-types.h index 3e2fbd777f..3da572ba78 100644 --- a/runtime-light/tl/tl-types.h +++ b/runtime-light/tl/tl-types.h @@ -562,6 +562,11 @@ class span { }; span() noexcept = default; + span(const span&) noexcept = default; + span(span&&) noexcept = default; + span& operator=(const span&) noexcept = default; + span& operator=(span&&) noexcept = default; + ~span() = default; template requires std::constructible_from && tl::deserializable && std::default_initializable From 292da387baa56a7fe83681268a817b210307056e Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 11:53:03 +0300 Subject: [PATCH 37/48] added from_bytes for tl::span --- runtime-light/tl/tl-types.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/runtime-light/tl/tl-types.h b/runtime-light/tl/tl-types.h index 3da572ba78..4496ff431d 100644 --- a/runtime-light/tl/tl-types.h +++ b/runtime-light/tl/tl-types.h @@ -618,6 +618,18 @@ class span { return this->m_size.footprint() + this->m_data.size(); } + void from_bytes(std::span serialized_data) noexcept { + tl::fetcher tlf{this->m_data}; + size_t size{}; + while (T{}.fetch(tlf)) { + size++; + } + + kphp::log::assertion(tlf.remaining() == 0); + this->m_data = serialized_data; + this->m_size = size; + } + std::span into_bytes() const noexcept { return this->m_data; } From bd72a56a46ec30d85d7e973f8f26a0802d651541 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 12:01:24 +0300 Subject: [PATCH 38/48] fix tl scheme --- runtime-light/stdlib/diagnostics/metric.tl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metric.tl b/runtime-light/stdlib/diagnostics/metric.tl index 76b3427348..60b0ffbe64 100644 --- a/runtime-light/stdlib/diagnostics/metric.tl +++ b/runtime-light/stdlib/diagnostics/metric.tl @@ -7,7 +7,7 @@ span#dad3ae87 {t:Type} count:# data:count*[t] = Span t; metricValue#0cb5eb87 value:double = MetricValue; metricValuesArray#d4a59582 values:%(Span double) = MetricValue; -metricCount#941bf7d1 count:int = MetricValue; +metricCount#941bf7d1 count:u32 = MetricValue; metricInc#23e305ab = MetricValue; -metric#87d62ee3 timestamp:long value:MetricValue metric_name:string tags:%(Span %(Pair string string)) = Metric; +metric#87d62ee3 timestamp:u64 value:MetricValue metric_name:string tags:%(Span %(Pair string string)) = Metric; From 1fef69eb95a8aaccdf61a177c83ea01d275dbe9e Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 12:34:38 +0300 Subject: [PATCH 39/48] removed tl::span, moved metrics tl classes --- runtime-light/stdlib/diagnostics/metrics.h | 108 ++++++++- runtime-light/tl/tl-types.h | 267 --------------------- 2 files changed, 106 insertions(+), 269 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 26308d3931..425cef8f0e 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -21,6 +21,111 @@ #include "runtime-light/tl/tl-core.h" #include "runtime-light/tl/tl-types.h" +namespace tl { + +class MetricValue final { + static constexpr uint32_t MAGIC = 0xcb5eb87U; + +public: + tl::f64 value; + + void store(tl::storer& tls) const noexcept { + tl::magic{.value = MetricValue::MAGIC}.store(tls); + value.store(tls); + } + + constexpr size_t footprint() const noexcept { + return tl::magic{.value = MetricValue::MAGIC}.footprint() + value.footprint(); + } +}; + +class MetricValuesArray final { + static constexpr uint32_t MAGIC = 0xd4a59582U; + +public: + std::span values; + + void store(tl::storer& tls) const noexcept { + tl::magic{.value = MetricValuesArray::MAGIC}.store(tls); + tl::u32{static_cast(this->values.size())}.store(tls); + std::ranges::for_each(this->values, [&tls](const double& elem) noexcept { tl::f64{elem}.store(tls); }); + } + + constexpr size_t footprint() const noexcept { + return tl::magic{.value = MetricValuesArray::MAGIC}.footprint() + + std::ranges::fold_left(this->values, tl::u32{static_cast(this->values.size())}.footprint(), + [](size_t acc, const double& elem) noexcept { return acc + tl::f64{elem}.footprint(); }); + } +}; + +class MetricCount final { + static constexpr uint32_t MAGIC = 0x941bf7d1U; + +public: + tl::u32 count; + + void store(tl::storer& tls) const noexcept { + tl::magic{.value = MetricCount::MAGIC}.store(tls); + count.store(tls); + } + + constexpr size_t footprint() const noexcept { + return tl::magic{.value = MetricCount::MAGIC}.footprint() + count.footprint(); + } +}; + +class MetricInc final { + static constexpr uint32_t MAGIC = 0x23e305abU; + +public: + void store(tl::storer& tls) const noexcept { + tl::magic{.value = MetricInc::MAGIC}.store(tls); + } + + constexpr size_t footprint() const noexcept { + return tl::magic{.value = MetricInc::MAGIC}.footprint(); + } +}; + +struct anyMetricValue final { + std::variant value; + + void store(tl::storer& tls) const noexcept { + std::visit([&tls](const auto& v) noexcept { v.store(tls); }, value); + } + + constexpr size_t footprint() const noexcept { + return std::visit([](const auto& v) noexcept { return v.footprint(); }, value); + } +}; + +template +requires std::same_as>, tl::pair> +struct metric final { + tl::u64 timestamp; + tl::anyMetricValue value; + tl::string metric_name; + TagRange tags; + + void store(tl::storer& tls) const noexcept { + timestamp.store(tls); + value.store(tls); + metric_name.store(tls); + + tl::u32{.value = static_cast(std::ranges::distance(tags))}.store(tls); + std::ranges::for_each(tags, [&tls](const auto& elem) noexcept { elem.store(tls); }); + } + + constexpr size_t footprint() const noexcept { + return timestamp.footprint() + value.footprint() + metric_name.footprint() + + std::ranges::fold_left(tags, tl::u32{.value = static_cast(std::ranges::distance(tags))}.footprint(), + [](size_t acc, const auto& elem) noexcept { return acc + elem.footprint(); }); + } +}; +} // namespace tl + +// --------------------------------------------------------------------------------------------------------- + namespace kphp::diagnostics { template concept tag_range = std::ranges::range && std::is_constructible_v, std::ranges::range_value_t>; @@ -94,8 +199,7 @@ struct metric final { template decltype(auto) send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), - tl::anyMetricValue{tl::MetricValuesArray{tl::span{values}}}, timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::anyMetricValue{tl::MetricValuesArray{values}}, timestamp); } template diff --git a/runtime-light/tl/tl-types.h b/runtime-light/tl/tl-types.h index 4496ff431d..c0b0f2bf57 100644 --- a/runtime-light/tl/tl-types.h +++ b/runtime-light/tl/tl-types.h @@ -9,9 +9,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -505,172 +503,6 @@ struct pair final { } }; -template -class span { - static constexpr bool supports_iteration = tl::deserializable && std::default_initializable; - std::span m_data; - tl::u32 m_size; - -public: - struct const_iterator { - private: - tl::fetcher tlf; - std::optional value; - - public: - using iterator_category = std::input_iterator_tag; - using value_type = const T; - using difference_type = std::ptrdiff_t; - using pointer = const T*; - using reference = const T&; - - explicit const_iterator(tl::fetcher tlf, std::optional value) noexcept - : tlf{std::move(tlf)}, - value{std::move(value)} {} - - reference operator*() const noexcept { - kphp::log::assertion(this->value.has_value()); - return this->value.value(); - } - - pointer operator->() const noexcept { - kphp::log::assertion(this->value.has_value()); - return std::addressof(this->value.value()); - } - - const_iterator& operator++() noexcept { - if (tlf.remaining() == 0) { // the end - this->value = std::nullopt; - return *this; - } - - kphp::log::assertion(this->value.has_value()); - kphp::log::assertion(this->value->fetch(this->tlf)); - return *this; - } - - const_iterator operator++(int) noexcept { // NOLINT - const_iterator tmp{*this}; - ++*this; - return tmp; - } - - // are equal if the same data and the same position, and both (or none of them) are end() (latter is checked by comparing with has_value()) - bool operator==(const const_iterator& other) const noexcept { - return this->tlf.view().data() == other.tlf.view().data() && this->tlf.pos() == other.tlf.pos() && this->value.has_value() == other.value.has_value(); - } - }; - - span() noexcept = default; - span(const span&) noexcept = default; - span(span&&) noexcept = default; - span& operator=(const span&) noexcept = default; - span& operator=(span&&) noexcept = default; - ~span() = default; - - template - requires std::constructible_from && tl::deserializable && std::default_initializable - explicit span(std::span items) noexcept - : m_data{std::as_bytes(items)}, - m_size{tl::u32{static_cast(items.size())}} { - tl::fetcher tlf{this->m_data}; - size_t count{}; - while (T{}.fetch(tlf)) { - count++; - } - - kphp::log::assertion(tlf.remaining() == 0); - kphp::log::assertion(items.size() == count); - } - - bool fetch(tl::fetcher& tlf) noexcept - requires tl::deserializable && std::default_initializable - { - // fetch data len - tl::u32 size{}; - if (!size.fetch(tlf)) { - return false; - } - - const std::byte* tlf_data{tlf.view().data()}; - size_t pos_start{tlf.pos()}; - - // skip objects - T tmp{}; - if (!std::ranges::fold_left(std::ranges::iota_view(uint32_t{0}, size.value), true, - [&tmp, &tlf](bool acc, const auto&) noexcept { return acc && tmp.fetch(tlf); })) { - return false; - } - - // write data - size_t pos_end{tlf.pos()}; - this->m_data = std::span{tlf_data + pos_start, pos_end - pos_start}; - this->m_size = size; - return true; - } - - void store(tl::storer& tls) const noexcept { - this->m_size.store(tls); - tls.store_bytes(this->m_data); - } - - constexpr size_t footprint() const noexcept { - return this->m_size.footprint() + this->m_data.size(); - } - - void from_bytes(std::span serialized_data) noexcept { - tl::fetcher tlf{this->m_data}; - size_t size{}; - while (T{}.fetch(tlf)) { - size++; - } - - kphp::log::assertion(tlf.remaining() == 0); - this->m_data = serialized_data; - this->m_size = size; - } - - std::span into_bytes() const noexcept { - return this->m_data; - } - - size_t size() const noexcept { - return this->m_size.value; - } - - const_iterator begin() const noexcept - requires supports_iteration - { - return this->cbegin(); - } - - const_iterator end() const noexcept - requires supports_iteration - { - return this->cend(); - } - - const_iterator cbegin() const noexcept - requires supports_iteration - { - tl::fetcher tlf{m_data}; - if (this->m_data.empty()) [[unlikely]] { - return const_iterator{tlf, std::nullopt}; - } - T value{}; - kphp::log::assertion(value.fetch(tlf)); - return const_iterator{std::move(tlf), std::move(value)}; - } - - const_iterator cend() const noexcept - requires supports_iteration - { - tl::fetcher tlf{m_data}; - tlf.adjust(tlf.remaining()); - return const_iterator{tlf, std::nullopt}; - } -}; - template struct Vector final { tl::vector inner{}; @@ -1879,105 +1711,6 @@ class CompositeWebTransferWaitUpdatesResultOk final { } }; -// ===== METRICS ===== - -class MetricValue final { - static constexpr uint32_t MAGIC = 0xcb5eb87U; - -public: - tl::f64 value; - - void store(tl::storer& tls) const noexcept { - tl::magic{.value = MetricValue::MAGIC}.store(tls); - value.store(tls); - } - - constexpr size_t footprint() const noexcept { - return tl::magic{.value = MetricValue::MAGIC}.footprint() + value.footprint(); - } -}; - -class MetricValuesArray final { - static constexpr uint32_t MAGIC = 0xd4a59582U; - -public: - tl::span values; - - void store(tl::storer& tls) const noexcept { - tl::magic{.value = MetricValuesArray::MAGIC}.store(tls); - values.store(tls); - } - - constexpr size_t footprint() const noexcept { - return tl::magic{.value = MetricValuesArray::MAGIC}.footprint() + values.footprint(); - } -}; - -class MetricCount final { - static constexpr uint32_t MAGIC = 0x941bf7d1U; - -public: - tl::u32 count; - - void store(tl::storer& tls) const noexcept { - tl::magic{.value = MetricCount::MAGIC}.store(tls); - count.store(tls); - } - - constexpr size_t footprint() const noexcept { - return tl::magic{.value = MetricCount::MAGIC}.footprint() + count.footprint(); - } -}; - -class MetricInc final { - static constexpr uint32_t MAGIC = 0x23e305abU; - -public: - void store(tl::storer& tls) const noexcept { - tl::magic{.value = MetricInc::MAGIC}.store(tls); - } - - constexpr size_t footprint() const noexcept { - return tl::magic{.value = MetricInc::MAGIC}.footprint(); - } -}; - -struct anyMetricValue final { - std::variant value; - - void store(tl::storer& tls) const noexcept { - std::visit([&tls](const auto& v) noexcept { v.store(tls); }, value); - } - - constexpr size_t footprint() const noexcept { - return std::visit([](const auto& v) noexcept { return v.footprint(); }, value); - } -}; - -template -requires std::same_as>, tl::pair> -struct metric final { - tl::u64 timestamp; - tl::anyMetricValue value; - tl::string metric_name; - TagRange tags; - - void store(tl::storer& tls) const noexcept { - timestamp.store(tls); - value.store(tls); - metric_name.store(tls); - - tl::u32{.value = static_cast(std::ranges::distance(tags))}.store(tls); - std::ranges::for_each(tags, [&tls](const auto& elem) noexcept { elem.store(tls); }); - } - - constexpr size_t footprint() const noexcept { - return timestamp.footprint() + value.footprint() + metric_name.footprint() + - std::ranges::fold_left(tags, tl::u32{.value = static_cast(std::ranges::distance(tags))}.footprint(), - [](size_t acc, const auto& elem) noexcept { return acc + elem.footprint(); }); - } -}; - } // namespace tl namespace tl2 { From 954d130d3d0163d1fdd34f2e2e1163ed5875f37c Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 12:35:25 +0300 Subject: [PATCH 40/48] removed unused include --- runtime-light/tl/tl-types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime-light/tl/tl-types.h b/runtime-light/tl/tl-types.h index c0b0f2bf57..53f5a56ae1 100644 --- a/runtime-light/tl/tl-types.h +++ b/runtime-light/tl/tl-types.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include #include From b3b2335f6d4f04df56d38c87463b9a76f5e306cf Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 12:36:35 +0300 Subject: [PATCH 41/48] removed unused space --- runtime-light/stdlib/diagnostics/metrics.h | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 425cef8f0e..c0c24a0df6 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -22,7 +22,6 @@ #include "runtime-light/tl/tl-types.h" namespace tl { - class MetricValue final { static constexpr uint32_t MAGIC = 0xcb5eb87U; From 8308d75e5da712678279fb32cce0c5f58c8e03da Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 14:23:31 +0300 Subject: [PATCH 42/48] removed monitoring system enum --- runtime-light/k2-platform/k2-api.h | 6 ++-- runtime-light/k2-platform/k2-header.h | 5 +-- runtime-light/stdlib/diagnostics/metrics.h | 41 ++++++++++------------ 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 4651cc8a1d..22656b7381 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -72,8 +72,6 @@ using StreamStatus = StreamStatus; using UpdateStatus = UpdateStatus; -using MonitoringSystem = MonitoringSystem; - using TimePoint = TimePoint; using SystemTime = SystemTime; @@ -247,8 +245,8 @@ inline std::expected madvise(void* addr, size_t length, int32_t a return {}; } -inline std::expected write_metrics(std::span serialized_metric, k2::MonitoringSystem ms) noexcept { - if (auto error_code{k2_write_metrics(serialized_metric.data(), serialized_metric.size(), ms)}; error_code != k2::errno_ok) [[unlikely]] { +inline std::expected write_metrics(std::span serialized_metric) noexcept { + if (auto error_code{k2_write_metrics(serialized_metric.data(), serialized_metric.size())}; error_code != k2::errno_ok) [[unlikely]] { return std::unexpected{error_code}; } return {}; diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index cdd066c837..1dd9f13b7d 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -97,8 +97,6 @@ enum UpdateStatus { NewDescriptor = 2, }; -enum MonitoringSystem { StatsHouse }; - struct ImageInfo { // Base const char* image_name; @@ -407,10 +405,9 @@ int32_t k2_madvise(void* addr, size_t length, int32_t advise); * * @param `buf` A pointer to the serialized metric(s) data. * @param `buf_len` The length of the serialized metric(s) data in bytes. - * @param `ms` The target monitoring system. * @return returns 0 if everything is fine, otherwise error code */ -int32_t k2_write_metrics(const void* buf, size_t buf_len, enum MonitoringSystem ms); +int32_t k2_write_metrics(const void* buf, size_t buf_len); /** * Sets `StreamStatus.please_whutdown_write=true` for the component on the diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index c0c24a0df6..97f6e4787c 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -132,15 +132,12 @@ concept tag_range = std::ranges::range && std::is_constructible_v send() const noexcept { - return k2::write_metrics(this->tls.view(), this->ms); + return k2::write_metrics(this->tls.view()); } // clears buffer and returns it with preserved capacity for reuse by metric::with_buffer() std::expected send() && noexcept { - return k2::write_metrics(this->tls.view(), this->ms).transform([this]() noexcept { + return k2::write_metrics(this->tls.view()).transform([this]() noexcept { this->tls.clear(); return std::move(this->tls); }); @@ -181,12 +178,12 @@ struct metric final { } public: - static metric empty(k2::MonitoringSystem ms) noexcept { - return metric{ms}; + static metric empty() noexcept { + return metric{}; } - static metric with_buffer(tl::storer&& tls, k2::MonitoringSystem ms) noexcept { - return metric{std::move(tls), ms}; + static metric with_buffer(tl::storer&& tls) noexcept { + return metric{std::move(tls)}; } template @@ -221,15 +218,13 @@ struct metric_builder final { kphp::stl::vector, kphp::stl::string>, kphp::memory::script_allocator> tags; - k2::MonitoringSystem ms; - metric_builder(std::string_view metric_name, k2::MonitoringSystem ms) noexcept - : metric_name{metric_name}, - ms{ms} {} + explicit metric_builder(std::string_view metric_name) noexcept + : metric_name{metric_name} {} public: - static metric_builder metric(std::string_view metric_name, k2::MonitoringSystem ms) noexcept { - return metric_builder{metric_name, ms}; + static metric_builder metric(std::string_view metric_name) noexcept { + return metric_builder{metric_name}; } metric_builder& tag(std::string_view tag_name, std::string_view tag_value) noexcept { @@ -238,19 +233,19 @@ struct metric_builder final { } auto send_value(double value, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_value(this->metric_name, this->tags, value, timestamp); + return metric::empty().send_value(this->metric_name, this->tags, value, timestamp); } auto send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_values_array(this->metric_name, this->tags, values, timestamp); + return metric::empty().send_values_array(this->metric_name, this->tags, values, timestamp); } auto send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_count(this->metric_name, this->tags, count, timestamp); + return metric::empty().send_count(this->metric_name, this->tags, count, timestamp); } auto send_increment(std::optional timestamp = std::nullopt) const noexcept { - return metric::empty(this->ms).send_increment(this->metric_name, this->tags, timestamp); + return metric::empty().send_increment(this->metric_name, this->tags, timestamp); } }; } // namespace kphp::diagnostics From 787afac197e6c31f1eec7b4bb9fa9852fa26348d Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 17:16:56 +0300 Subject: [PATCH 43/48] fix metric tl classes --- runtime-light/stdlib/diagnostics/metric.tl | 10 ++-- runtime-light/stdlib/diagnostics/metrics.h | 66 ++++++++++++---------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metric.tl b/runtime-light/stdlib/diagnostics/metric.tl index 60b0ffbe64..1dbed73579 100644 --- a/runtime-light/stdlib/diagnostics/metric.tl +++ b/runtime-light/stdlib/diagnostics/metric.tl @@ -5,9 +5,9 @@ span#dad3ae87 {t:Type} count:# data:count*[t] = Span t; // Metric -metricValue#0cb5eb87 value:double = MetricValue; -metricValuesArray#d4a59582 values:%(Span double) = MetricValue; -metricCount#941bf7d1 count:u32 = MetricValue; -metricInc#23e305ab = MetricValue; +metricValue#0cb5eb87 value:double = AnyMetricValue; +metricValuesArray#d4a59582 values:%(Span double) = AnyMetricValue; +metricCount#941bf7d1 count:u32 = AnyMetricValue; +metricInc#23e305ab = AnyMetricValue; -metric#87d62ee3 timestamp:u64 value:MetricValue metric_name:string tags:%(Span %(Pair string string)) = Metric; +metric#87d62ee3 timestamp:u64 value:AnyMetricValue metric_name:string tags:%(Span %(Pair string string)) = Metric; diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 97f6e4787c..08fca7ca9a 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "runtime-common/core/allocator/script-allocator.h" #include "runtime-common/core/std/containers.h" @@ -22,79 +23,82 @@ #include "runtime-light/tl/tl-types.h" namespace tl { -class MetricValue final { - static constexpr uint32_t MAGIC = 0xcb5eb87U; +class metricValue final { public: tl::f64 value; void store(tl::storer& tls) const noexcept { - tl::magic{.value = MetricValue::MAGIC}.store(tls); value.store(tls); } constexpr size_t footprint() const noexcept { - return tl::magic{.value = MetricValue::MAGIC}.footprint() + value.footprint(); + return value.footprint(); } }; -class MetricValuesArray final { - static constexpr uint32_t MAGIC = 0xd4a59582U; - +class metricValuesArray final { public: std::span values; void store(tl::storer& tls) const noexcept { - tl::magic{.value = MetricValuesArray::MAGIC}.store(tls); tl::u32{static_cast(this->values.size())}.store(tls); std::ranges::for_each(this->values, [&tls](const double& elem) noexcept { tl::f64{elem}.store(tls); }); } constexpr size_t footprint() const noexcept { - return tl::magic{.value = MetricValuesArray::MAGIC}.footprint() + - std::ranges::fold_left(this->values, tl::u32{static_cast(this->values.size())}.footprint(), + return std::ranges::fold_left(this->values, tl::u32{static_cast(this->values.size())}.footprint(), [](size_t acc, const double& elem) noexcept { return acc + tl::f64{elem}.footprint(); }); } }; -class MetricCount final { - static constexpr uint32_t MAGIC = 0x941bf7d1U; - +class metricCount final { public: tl::u32 count; void store(tl::storer& tls) const noexcept { - tl::magic{.value = MetricCount::MAGIC}.store(tls); count.store(tls); } constexpr size_t footprint() const noexcept { - return tl::magic{.value = MetricCount::MAGIC}.footprint() + count.footprint(); + return count.footprint(); } }; -class MetricInc final { - static constexpr uint32_t MAGIC = 0x23e305abU; - +class metricInc final { public: - void store(tl::storer& tls) const noexcept { - tl::magic{.value = MetricInc::MAGIC}.store(tls); - } + void store(tl::storer& /* tls */) const noexcept {} constexpr size_t footprint() const noexcept { - return tl::magic{.value = MetricInc::MAGIC}.footprint(); + return 0; } }; -struct anyMetricValue final { - std::variant value; +class AnyMetricValue final { + static constexpr uint32_t VALUE_MAGIC = 0xcb5eb87U; + static constexpr uint32_t VALUES_ARRAY_MAGIC = 0xd4a59582U; + static constexpr uint32_t COUNT_MAGIC = 0x941bf7d1U; + static constexpr uint32_t INC_MAGIC = 0x23e305abU; + +public: + std::variant value; void store(tl::storer& tls) const noexcept { + if (std::holds_alternative(value)) { + tl::magic{.value = AnyMetricValue::VALUE_MAGIC}.store(tls); + } else if (std::holds_alternative(value)) { + tl::magic{.value = AnyMetricValue::VALUES_ARRAY_MAGIC}.store(tls); + } else if (std::holds_alternative(value)) { + tl::magic{.value = AnyMetricValue::COUNT_MAGIC}.store(tls); + } else { + tl::magic{.value = AnyMetricValue::INC_MAGIC}.store(tls); + } + std::visit([&tls](const auto& v) noexcept { v.store(tls); }, value); } constexpr size_t footprint() const noexcept { - return std::visit([](const auto& v) noexcept { return v.footprint(); }, value); + return tl::magic{}.footprint() + std::visit([](const auto& v) noexcept { return v.footprint(); }, value); } }; @@ -102,7 +106,7 @@ template requires std::same_as>, tl::pair> struct metric final { tl::u64 timestamp; - tl::anyMetricValue value; + tl::AnyMetricValue value; tl::string metric_name; TagRange tags; @@ -158,7 +162,7 @@ struct metric final { } template - decltype(auto) build_and_send(this Self&& self, std::string_view metric_name, TagRange&& tags, tl::anyMetricValue value, + decltype(auto) build_and_send(this Self&& self, std::string_view metric_name, TagRange&& tags, tl::AnyMetricValue value, std::optional timestamp) noexcept { self.tls.clear(); @@ -189,24 +193,24 @@ struct metric final { template decltype(auto) send_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::anyMetricValue{tl::MetricValue{tl::f64{value}}}, timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricValue{tl::f64{value}}}, timestamp); } template decltype(auto) send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::anyMetricValue{tl::MetricValuesArray{values}}, timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricValuesArray{values}}, timestamp); } template decltype(auto) send_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::anyMetricValue{tl::MetricCount{tl::u32{count}}}, timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricCount{tl::u32{count}}}, timestamp); } template decltype(auto) send_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::anyMetricValue{tl::MetricInc{}}, timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricInc{}}, timestamp); } }; From 54003fbab9d9b069dba36107420695cdf8e73a19 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 17:24:26 +0300 Subject: [PATCH 44/48] added {} --- runtime-light/stdlib/diagnostics/metrics.h | 25 +++++++++------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 08fca7ca9a..90d3ef313a 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -23,10 +23,8 @@ #include "runtime-light/tl/tl-types.h" namespace tl { -class metricValue final { - -public: - tl::f64 value; +struct metricValue final { + tl::f64 value{}; void store(tl::storer& tls) const noexcept { value.store(tls); @@ -37,8 +35,7 @@ class metricValue final { } }; -class metricValuesArray final { -public: +struct metricValuesArray final { std::span values; void store(tl::storer& tls) const noexcept { @@ -52,9 +49,8 @@ class metricValuesArray final { } }; -class metricCount final { -public: - tl::u32 count; +struct metricCount final { + tl::u32 count{}; void store(tl::storer& tls) const noexcept { count.store(tls); @@ -65,8 +61,7 @@ class metricCount final { } }; -class metricInc final { -public: +struct metricInc final { void store(tl::storer& /* tls */) const noexcept {} constexpr size_t footprint() const noexcept { @@ -105,10 +100,10 @@ class AnyMetricValue final { template requires std::same_as>, tl::pair> struct metric final { - tl::u64 timestamp; - tl::AnyMetricValue value; - tl::string metric_name; - TagRange tags; + tl::u64 timestamp{}; + tl::AnyMetricValue value{}; + tl::string metric_name{}; + TagRange tags{}; void store(tl::storer& tls) const noexcept { timestamp.store(tls); From 0a1c7a44594c14b9e36e1268320cec5a231b775f Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 17:41:18 +0300 Subject: [PATCH 45/48] added requires --- runtime-light/stdlib/diagnostics/metrics.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 90d3ef313a..f78c88ad8e 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -105,7 +105,9 @@ struct metric final { tl::string metric_name{}; TagRange tags{}; - void store(tl::storer& tls) const noexcept { + void store(tl::storer& tls) const noexcept + requires tl::serializable> + { timestamp.store(tls); value.store(tls); metric_name.store(tls); @@ -114,7 +116,9 @@ struct metric final { std::ranges::for_each(tags, [&tls](const auto& elem) noexcept { elem.store(tls); }); } - constexpr size_t footprint() const noexcept { + constexpr size_t footprint() const noexcept + requires tl::footprintable> + { return timestamp.footprint() + value.footprint() + metric_name.footprint() + std::ranges::fold_left(tags, tl::u32{.value = static_cast(std::ranges::distance(tags))}.footprint(), [](size_t acc, const auto& elem) noexcept { return acc + elem.footprint(); }); From 6b6b30323d4820ba0437e2d6c7329e443988ebe2 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 29 Jun 2026 18:04:52 +0300 Subject: [PATCH 46/48] send && fixed --- runtime-light/stdlib/diagnostics/metrics.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index f78c88ad8e..0914d4fa2e 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -153,11 +153,10 @@ struct metric final { } // clears buffer and returns it with preserved capacity for reuse by metric::with_buffer() - std::expected send() && noexcept { - return k2::write_metrics(this->tls.view()).transform([this]() noexcept { - this->tls.clear(); - return std::move(this->tls); - }); + std::pair> send() && noexcept { + std::expected send_result{k2::write_metrics(this->tls.view())}; + this->tls.clear(); + return std::pair{std::move(this->tls), std::move(send_result)}; } template From e4bd9e8cdb882390c0b81297dba543900bcde3bc Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 30 Jun 2026 15:53:19 +0300 Subject: [PATCH 47/48] fixes --- runtime-light/stdlib/diagnostics/metrics.h | 28 ++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index 0914d4fa2e..da6ce8ccb5 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -97,7 +97,7 @@ class AnyMetricValue final { } }; -template +template requires std::same_as>, tl::pair> struct metric final { tl::u64 timestamp{}; @@ -129,6 +129,10 @@ struct metric final { // --------------------------------------------------------------------------------------------------------- namespace kphp::diagnostics { +template +concept values_range = std::ranges::range && std::same_as>, double> && + std::is_constructible_v, ValuesRange>; + template concept tag_range = std::ranges::range && std::is_constructible_v, std::ranges::range_value_t>; @@ -189,25 +193,24 @@ struct metric final { } template - decltype(auto) send_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, - std::optional timestamp = std::nullopt) noexcept { + auto send_value(this Self&& self, std::string_view metric_name, TagRange&& tags, double value, std::optional timestamp = std::nullopt) noexcept { return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricValue{tl::f64{value}}}, timestamp); } - template - decltype(auto) send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, - std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricValuesArray{values}}, timestamp); + template + auto send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, ValuesRange&& values, + std::optional timestamp = std::nullopt) noexcept { + return std::forward(self).build_and_send(metric_name, std::forward(tags), + tl::AnyMetricValue{tl::metricValuesArray{std::forward(values)}}, timestamp); } template - decltype(auto) send_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, - std::optional timestamp = std::nullopt) noexcept { + auto send_count(this Self&& self, std::string_view metric_name, TagRange&& tags, uint32_t count, std::optional timestamp = std::nullopt) noexcept { return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricCount{tl::u32{count}}}, timestamp); } template - decltype(auto) send_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { + auto send_increment(this Self&& self, std::string_view metric_name, TagRange&& tags, std::optional timestamp = std::nullopt) noexcept { return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricInc{}}, timestamp); } }; @@ -238,8 +241,9 @@ struct metric_builder final { return metric::empty().send_value(this->metric_name, this->tags, value, timestamp); } - auto send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty().send_values_array(this->metric_name, this->tags, values, timestamp); + template + auto send_values_array(ValuesRange&& values, std::optional timestamp = std::nullopt) const noexcept { + return metric::empty().send_values_array(this->metric_name, this->tags, std::forward(values), timestamp); } auto send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept { From 28a27730d16cb3b1cdc48122aec1e19378c776ed Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 30 Jun 2026 15:56:10 +0300 Subject: [PATCH 48/48] fixes --- runtime-light/stdlib/diagnostics/metrics.h | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/runtime-light/stdlib/diagnostics/metrics.h b/runtime-light/stdlib/diagnostics/metrics.h index da6ce8ccb5..74b9bce9ca 100644 --- a/runtime-light/stdlib/diagnostics/metrics.h +++ b/runtime-light/stdlib/diagnostics/metrics.h @@ -129,10 +129,6 @@ struct metric final { // --------------------------------------------------------------------------------------------------------- namespace kphp::diagnostics { -template -concept values_range = std::ranges::range && std::same_as>, double> && - std::is_constructible_v, ValuesRange>; - template concept tag_range = std::ranges::range && std::is_constructible_v, std::ranges::range_value_t>; @@ -197,11 +193,10 @@ struct metric final { return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricValue{tl::f64{value}}}, timestamp); } - template - auto send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, ValuesRange&& values, + template + auto send_values_array(this Self&& self, std::string_view metric_name, TagRange&& tags, std::span values, std::optional timestamp = std::nullopt) noexcept { - return std::forward(self).build_and_send(metric_name, std::forward(tags), - tl::AnyMetricValue{tl::metricValuesArray{std::forward(values)}}, timestamp); + return std::forward(self).build_and_send(metric_name, std::forward(tags), tl::AnyMetricValue{tl::metricValuesArray{values}}, timestamp); } template @@ -241,9 +236,8 @@ struct metric_builder final { return metric::empty().send_value(this->metric_name, this->tags, value, timestamp); } - template - auto send_values_array(ValuesRange&& values, std::optional timestamp = std::nullopt) const noexcept { - return metric::empty().send_values_array(this->metric_name, this->tags, std::forward(values), timestamp); + auto send_values_array(std::span values, std::optional timestamp = std::nullopt) const noexcept { + return metric::empty().send_values_array(this->metric_name, this->tags, values, timestamp); } auto send_count(uint32_t count, std::optional timestamp = std::nullopt) const noexcept {