Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
694884f
first version
denisichh Jun 19, 2026
2b7be26
added metric builder + write_serialized_metric to k2-api
denisichh Jun 19, 2026
7bb602d
v1.0
denisichh Jun 19, 2026
f6af9d2
v1.1
denisichh Jun 21, 2026
0608cf2
rename
denisichh Jun 21, 2026
12b21ac
mask size 32bits to 8bits
denisichh Jun 21, 2026
5bb69d9
fixes
denisichh Jun 22, 2026
f8f635f
fixes
denisichh Jun 22, 2026
064d869
add comments
denisichh Jun 22, 2026
de690e2
added noexcept
denisichh Jun 22, 2026
127f856
fixes
denisichh Jun 22, 2026
537b967
minor fix
denisichh Jun 22, 2026
22a6227
added metric type
denisichh Jun 22, 2026
86f1de8
fixes
denisichh Jun 22, 2026
22cdf85
timestamp u32 to u64 + fixes
denisichh Jun 23, 2026
21e5bdb
fix
denisichh Jun 23, 2026
88709e2
fix
denisichh Jun 23, 2026
4590662
fix concept
denisichh Jun 23, 2026
6f3052d
new metrics ctors
denisichh Jun 23, 2026
57d6b2e
rename static method
denisichh Jun 23, 2026
a5f3057
funny fixes
denisichh Jun 23, 2026
6c9137b
minor fix
denisichh Jun 23, 2026
9c63912
minor fix
denisichh Jun 23, 2026
713b47a
returned buffer.clear()
denisichh Jun 23, 2026
a7e392f
fix
denisichh Jun 23, 2026
b1d7add
added include
denisichh Jun 23, 2026
dfd5c0c
chrono to k2::system_time
denisichh Jun 23, 2026
9c5b54e
format changed: my own to tl
denisichh Jun 25, 2026
476e9cf
fixes
denisichh Jun 26, 2026
9e23659
fixes
denisichh Jun 26, 2026
3366cb6
minor rename
denisichh Jun 26, 2026
0ca6ecd
minor fix
denisichh Jun 26, 2026
3fc576a
added tl scheme fot metric type
denisichh Jun 26, 2026
6c6e917
fix .tl
denisichh Jun 26, 2026
67a07ff
added tl::span
denisichh Jun 29, 2026
202accd
rule of 5 for tl::span
denisichh Jun 29, 2026
292da38
added from_bytes for tl::span
denisichh Jun 29, 2026
bd72a56
fix tl scheme
denisichh Jun 29, 2026
1fef69e
removed tl::span, moved metrics tl classes
denisichh Jun 29, 2026
954d130
removed unused include
denisichh Jun 29, 2026
b3b2335
removed unused space
denisichh Jun 29, 2026
8308d75
removed monitoring system enum
denisichh Jun 29, 2026
787afac
fix metric tl classes
denisichh Jun 29, 2026
54003fb
added {}
denisichh Jun 29, 2026
0a1c7a4
added requires
denisichh Jun 29, 2026
6b6b303
send && fixed
denisichh Jun 29, 2026
e4bd9e8
fixes
denisichh Jun 30, 2026
28a2773
fixes
denisichh Jun 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions runtime-light/k2-platform/k2-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <utility>

#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

Expand Down Expand Up @@ -72,6 +74,10 @@ using StreamStatus = StreamStatus;

using UpdateStatus = UpdateStatus;

using MonitoringSystem = MonitoringSystem;

using MetricValueMask = MetricValueMask;

using TimePoint = TimePoint;

using SystemTime = SystemTime;
Expand Down Expand Up @@ -245,6 +251,10 @@ inline std::expected<void, int32_t> madvise(void* addr, size_t length, int32_t a
return {};
}

inline void write_metric(const kphp::stl::vector<uint8_t, kphp::memory::script_allocator>& serialized_metric, k2::MonitoringSystem ms) noexcept {
Comment thread
apolyakov marked this conversation as resolved.
Outdated
k2_write_metric(serialized_metric.data(), serialized_metric.size(), ms);
}

inline void please_shutdown(k2::descriptor descriptor) noexcept {
k2_please_shutdown(descriptor);
}
Expand Down
25 changes: 25 additions & 0 deletions runtime-light/k2-platform/k2-header.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ enum UpdateStatus {
NewDescriptor = 2,
};

enum MonitoringSystem { StatsHouse };

/*
* Serialized metric format:
* <timestamp_u32><value_format><msg_size><metric_name_len><metric_name><tag1_name_len><tag1_name><tag1_value_len><tag1_value>...
Comment thread
apolyakov marked this conversation as resolved.
Outdated
Comment thread
apolyakov marked this conversation as resolved.
Outdated
*
* value_format:
* <VALUE_MASK><f64> - single float value
* <VALUES_ARRAY_MASK><array_len><f64_1><f64_2>... - array of float values
* <COUNT_MASK><f64> - count value
* <INC_MASK> - counter increment (no payload)
*/
enum MetricValueMask : uint8_t { VALUE_MASK = 0, VALUES_ARRAY_MASK = 1, COUNT_MASK = 2, INC_MASK = 3 };

struct ImageInfo {
// Base
const char* image_name;
Expand Down Expand Up @@ -383,6 +397,17 @@ void* k2_mmap(uint64_t* md, void* addr, size_t length, int32_t prot, int32_t fla
*/
int32_t k2_madvise(void* addr, size_t length, int32_t advise);

/**
* Writes a pre-serialized metric to the specified monitoring system.
* The buffer must contain a metric serialized according to the format described above
* (see `MetricValueMask` and the serialized metric format comment).
*
* @param `buf` A pointer to the serialized metric data.
* @param `buf_len` The length of the serialized metric data in bytes.
* @param `ms` The target monitoring system.
*/
void k2_write_metric(const uint8_t* buf, size_t buf_len, enum MonitoringSystem ms);
Comment thread
apolyakov marked this conversation as resolved.
Outdated

/**
* Sets `StreamStatus.please_whutdown_write=true` for the component on the
* opposite side (does not affect `StreamStatus` on your side).
Expand Down
126 changes: 126 additions & 0 deletions runtime-light/stdlib/diagnostics/metrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Compiler for PHP (aka KPHP)
// Copyright (c) 2026 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#pragma once

#include <chrono>
#include <cstddef>
#include <cstdint>

#include "common/mixin/movable_only.h"
#include "runtime-common/core/allocator/script-allocator.h"
#include "runtime-common/core/std/containers.h"
#include "runtime-light/k2-platform/k2-api.h"

struct MetricBuilder final : vk::movable_only {
Comment thread
apolyakov marked this conversation as resolved.
Outdated
private:
using bytes_vector = kphp::stl::vector<uint8_t, kphp::memory::script_allocator>;
Comment thread
apolyakov marked this conversation as resolved.
Outdated
Comment thread
apolyakov marked this conversation as resolved.
Outdated

std::string metric_name;
Comment thread
apolyakov marked this conversation as resolved.
Outdated
kphp::stl::unordered_map<std::string, std::string, kphp::memory::script_allocator> tags;
size_t msg_size{0};

explicit MetricBuilder(std::string_view metric_name) noexcept
: metric_name{metric_name} {
this->msg_size += MetricBuilder::string_sizeof(metric_name);
}

template<typename T>
requires std::is_arithmetic_v<T>
static void store_number(bytes_vector& buf, const T& number) noexcept {
const auto* src = static_cast<const uint8_t*>(static_cast<const void*>(&number));
buf.insert(buf.end(), src, src + sizeof(T));
}

static void store_string(bytes_vector& buf, const std::string_view& string) noexcept {
MetricBuilder::store_number(buf, string.size());
buf.insert(buf.end(), string.begin(), string.end());
}

void store_msg(bytes_vector& buf) const noexcept {
MetricBuilder::store_number(buf, this->msg_size);
MetricBuilder::store_string(buf, std::string_view{this->metric_name.c_str(), this->metric_name.size()});
for (const auto& [tag_name, tag_value] : this->tags) {
MetricBuilder::store_string(buf, std::string_view{tag_name.c_str(), tag_name.size()});
MetricBuilder::store_string(buf, std::string_view{tag_value.c_str(), tag_value.size()});
}
}

static size_t string_sizeof(const std::string_view& string) noexcept {
return sizeof(size_t) + string.size();
}

static uint32_t s_timestamp_now() noexcept {
Comment thread
apolyakov marked this conversation as resolved.
Outdated
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}

public:
static MetricBuilder metric(std::string_view metric_name) noexcept {
return MetricBuilder{metric_name};
}

MetricBuilder& tag(std::string_view tag_name, std::string_view tag_value) noexcept {
this->tags[std::string{tag_name}] = std::string{tag_value};
this->msg_size += MetricBuilder::string_sizeof(tag_name) + MetricBuilder::string_sizeof(tag_value);
return *this;
}

bytes_vector build_value(double value, std::optional<uint32_t> timestamp = std::nullopt) const noexcept {
bytes_vector buf{};
buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) +
this->msg_size); // timestamp_u32 + value_mask_u8 + value_f64 + msg_size_usize + msg_len

uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())};

MetricBuilder::store_number(buf, s_timestamp);
MetricBuilder::store_number(buf, static_cast<uint8_t>(k2::MetricValueMask::VALUE_MASK));
MetricBuilder::store_number(buf, value);
this->store_msg(buf);
return buf;
}

bytes_vector build_values_array(const kphp::stl::vector<double, kphp::memory::script_allocator>& values,
std::optional<uint32_t> timestamp = std::nullopt) const noexcept {
bytes_vector buf{};
buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + sizeof(double) * values.size() + sizeof(size_t) +
this->msg_size); // timestamp_u32 + value_mask_u8 + array_len_usize + value_f64*array_len + msg_size_usize + msg_len

uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())};

MetricBuilder::store_number(buf, s_timestamp);
MetricBuilder::store_number(buf, static_cast<uint8_t>(k2::MetricValueMask::VALUES_ARRAY_MASK));
MetricBuilder::store_number(buf, values.size());
for (const auto& value : values) {
MetricBuilder::store_number(buf, value);
}
this->store_msg(buf);
return buf;
}

bytes_vector build_count(double count, std::optional<uint32_t> timestamp = std::nullopt) const noexcept {
bytes_vector buf{};
buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(double) + sizeof(size_t) +
this->msg_size); // timestamp_u32 + value_mask_u8 + count_f64 + msg_size_usize + msg_len

uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())};

MetricBuilder::store_number(buf, s_timestamp);
MetricBuilder::store_number(buf, static_cast<uint8_t>(k2::MetricValueMask::COUNT_MASK));
MetricBuilder::store_number(buf, count);
this->store_msg(buf);
return buf;
}

bytes_vector build_increment(std::optional<uint32_t> timestamp = std::nullopt) const noexcept {
bytes_vector buf{};
buf.reserve(sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t) + this->msg_size); // timestamp_u32 + value_mask_u8 + msg_size_usize + msg_len

uint32_t s_timestamp{timestamp.value_or(MetricBuilder::s_timestamp_now())};

MetricBuilder::store_number(buf, s_timestamp);
MetricBuilder::store_number(buf, static_cast<uint8_t>(k2::MetricValueMask::INC_MASK));
this->store_msg(buf);
return buf;
}
};
Loading