Use prometheus text format as LabelsKey representation
This commit is contained in:
300
src/metric.cpp
300
src/metric.cpp
@@ -134,15 +134,16 @@ static std::string_view arena_copy_string(std::string_view str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Arena-based labels key for second level of map
|
// Arena-based labels key for second level of map
|
||||||
// Uses string_view to point to arena-allocated strings
|
// Uses string_view containing labels in Prometheus text format
|
||||||
struct LabelsKey {
|
struct LabelsKey {
|
||||||
ArenaVector<std::pair<std::string_view, std::string_view>> labels;
|
std::string_view prometheus_format;
|
||||||
|
|
||||||
// Arena-owning constructor (copies strings into arena)
|
// Arena-owning constructor (copies strings into arena and formats as
|
||||||
|
// Prometheus text)
|
||||||
LabelsKey(std::span<const std::pair<std::string_view, std::string_view>> l,
|
LabelsKey(std::span<const std::pair<std::string_view, std::string_view>> l,
|
||||||
ArenaAllocator &arena)
|
ArenaAllocator &arena) {
|
||||||
: labels(&arena) {
|
// Copy and validate all label keys and values, sort by key
|
||||||
// Copy and validate all label keys and values into arena
|
ArenaVector<std::pair<std::string_view, std::string_view>> labels(&arena);
|
||||||
for (const auto &[key, value] : l) {
|
for (const auto &[key, value] : l) {
|
||||||
validate_or_abort(is_valid_label_key(key), "invalid label key", key);
|
validate_or_abort(is_valid_label_key(key), "invalid label key", key);
|
||||||
validate_or_abort(is_valid_label_value(value), "invalid label value",
|
validate_or_abort(is_valid_label_value(value), "invalid label value",
|
||||||
@@ -156,33 +157,67 @@ struct LabelsKey {
|
|||||||
// Sort labels by key for Prometheus compatibility
|
// Sort labels by key for Prometheus compatibility
|
||||||
std::sort(labels.data(), labels.data() + labels.size(),
|
std::sort(labels.data(), labels.data() + labels.size(),
|
||||||
[](const auto &a, const auto &b) { return a.first < b.first; });
|
[](const auto &a, const auto &b) { return a.first < b.first; });
|
||||||
|
|
||||||
|
// Generate Prometheus text format: {key1="value1",key2="value2"}
|
||||||
|
if (labels.empty()) {
|
||||||
|
prometheus_format = "";
|
||||||
|
} else {
|
||||||
|
// Calculate required size for formatted string
|
||||||
|
size_t required_size = 2; // {}
|
||||||
|
for (const auto &[key, value] : labels) {
|
||||||
|
required_size += key.length() + 3 + value.length(); // key="value"
|
||||||
|
for (char c : value) {
|
||||||
|
if (c == '\\' || c == '"' || c == '\n') {
|
||||||
|
required_size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
required_size += labels.size() - 1; // commas
|
||||||
|
|
||||||
|
// Generate formatted string in arena
|
||||||
|
char *buf = arena.allocate<char>(required_size);
|
||||||
|
char *p = buf;
|
||||||
|
|
||||||
|
*p++ = '{';
|
||||||
|
for (size_t i = 0; i < labels.size(); ++i) {
|
||||||
|
if (i > 0)
|
||||||
|
*p++ = ',';
|
||||||
|
std::memcpy(p, labels[i].first.data(), labels[i].first.length());
|
||||||
|
p += labels[i].first.length();
|
||||||
|
*p++ = '=';
|
||||||
|
*p++ = '"';
|
||||||
|
for (char c : labels[i].second) {
|
||||||
|
switch (c) {
|
||||||
|
case '\\':
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = '\\';
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = '"';
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = 'n';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*p++ = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p++ = '"';
|
||||||
|
}
|
||||||
|
*p++ = '}';
|
||||||
|
prometheus_format = std::string_view(buf, p - buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const LabelsKey &other) const {
|
bool operator==(const LabelsKey &other) const {
|
||||||
if (labels.size() != other.labels.size())
|
return prometheus_format == other.prometheus_format;
|
||||||
return false;
|
|
||||||
for (size_t i = 0; i < labels.size(); ++i) {
|
|
||||||
if (labels[i].first != other.labels[i].first ||
|
|
||||||
labels[i].second != other.labels[i].second) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const LabelsKey &other) const {
|
bool operator<(const LabelsKey &other) const {
|
||||||
if (labels.size() != other.labels.size()) {
|
return prometheus_format < other.prometheus_format;
|
||||||
return labels.size() < other.labels.size();
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < labels.size(); ++i) {
|
|
||||||
if (labels[i].first != other.labels[i].first) {
|
|
||||||
return labels[i].first < other.labels[i].first;
|
|
||||||
}
|
|
||||||
if (labels[i].second != other.labels[i].second) {
|
|
||||||
return labels[i].second < other.labels[i].second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false; // They are equal
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -191,16 +226,7 @@ struct LabelsKey {
|
|||||||
namespace std {
|
namespace std {
|
||||||
template <> struct hash<metric::LabelsKey> {
|
template <> struct hash<metric::LabelsKey> {
|
||||||
std::size_t operator()(const metric::LabelsKey &k) const {
|
std::size_t operator()(const metric::LabelsKey &k) const {
|
||||||
std::size_t hash_value = 0;
|
return std::hash<std::string_view>{}(k.prometheus_format);
|
||||||
for (size_t i = 0; i < k.labels.size(); ++i) {
|
|
||||||
const auto &[key, value] = k.labels[i];
|
|
||||||
// Combine hashes using a simple but effective method
|
|
||||||
hash_value ^= std::hash<std::string_view>{}(key) + 0x9e3779b9 +
|
|
||||||
(hash_value << 6) + (hash_value >> 2);
|
|
||||||
hash_value ^= std::hash<std::string_view>{}(value) + 0x9e3779b9 +
|
|
||||||
(hash_value << 6) + (hash_value >> 2);
|
|
||||||
}
|
|
||||||
return hash_value;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace std
|
} // namespace std
|
||||||
@@ -486,10 +512,10 @@ struct Metric {
|
|||||||
const LabelsKey &key = intern_labels(labels);
|
const LabelsKey &key = intern_labels(labels);
|
||||||
|
|
||||||
// Validate that labels aren't already registered as callback
|
// Validate that labels aren't already registered as callback
|
||||||
validate_or_abort(family->p->callbacks.find(key) ==
|
validate_or_abort(
|
||||||
family->p->callbacks.end(),
|
family->p->callbacks.find(key) == family->p->callbacks.end(),
|
||||||
"labels already registered as callback",
|
"labels already registered as callback",
|
||||||
key.labels.empty() ? "(no labels)" : key.labels[0].first);
|
key.prometheus_format.empty() ? "(no labels)" : key.prometheus_format);
|
||||||
|
|
||||||
// Ensure thread state exists
|
// Ensure thread state exists
|
||||||
auto thread_id = std::this_thread::get_id();
|
auto thread_id = std::this_thread::get_id();
|
||||||
@@ -519,10 +545,10 @@ struct Metric {
|
|||||||
const LabelsKey &key = intern_labels(labels);
|
const LabelsKey &key = intern_labels(labels);
|
||||||
|
|
||||||
// Validate that labels aren't already registered as callback
|
// Validate that labels aren't already registered as callback
|
||||||
validate_or_abort(family->p->callbacks.find(key) ==
|
validate_or_abort(
|
||||||
family->p->callbacks.end(),
|
family->p->callbacks.find(key) == family->p->callbacks.end(),
|
||||||
"labels already registered as callback",
|
"labels already registered as callback",
|
||||||
key.labels.empty() ? "(no labels)" : key.labels[0].first);
|
key.prometheus_format.empty() ? "(no labels)" : key.prometheus_format);
|
||||||
|
|
||||||
auto &ptr = family->p->instances[key];
|
auto &ptr = family->p->instances[key];
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
@@ -1210,38 +1236,29 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
|
|||||||
|
|
||||||
ArenaVector<std::string_view> output(&arena);
|
ArenaVector<std::string_view> output(&arena);
|
||||||
|
|
||||||
auto format_labels =
|
// Helper function to append an additional label to existing Prometheus format
|
||||||
[&](const ArenaVector<std::pair<std::string_view, std::string_view>>
|
auto append_label_to_format =
|
||||||
&labels) -> std::string_view {
|
[&](std::string_view base_format, std::string_view key,
|
||||||
if (labels.empty()) {
|
std::string_view value) -> std::string_view {
|
||||||
return "";
|
// Calculate size for key="value" with escaping
|
||||||
}
|
size_t key_value_size = key.length() + 3 + value.length(); // key="value"
|
||||||
|
|
||||||
size_t required_size = 2; // {}
|
|
||||||
for (const auto &[key, value] : labels) {
|
|
||||||
required_size += key.length() + 3 + value.length(); // key="value"
|
|
||||||
for (char c : value) {
|
for (char c : value) {
|
||||||
if (c == '\\' || c == '"' || c == '\n') {
|
if (c == '\\' || c == '"' || c == '\n') {
|
||||||
required_size++;
|
key_value_size++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!labels.empty()) {
|
|
||||||
required_size += labels.size() - 1; // commas
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (base_format.empty()) {
|
||||||
|
// Create new format: {key="value"}
|
||||||
|
size_t required_size = 2 + key_value_size; // {}
|
||||||
char *buf = arena.allocate<char>(required_size);
|
char *buf = arena.allocate<char>(required_size);
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
|
|
||||||
*p++ = '{';
|
*p++ = '{';
|
||||||
for (size_t i = 0; i < labels.size(); ++i) {
|
std::memcpy(p, key.data(), key.length());
|
||||||
if (i > 0)
|
p += key.length();
|
||||||
*p++ = ',';
|
|
||||||
std::memcpy(p, labels[i].first.data(), labels[i].first.length());
|
|
||||||
p += labels[i].first.length();
|
|
||||||
*p++ = '=';
|
*p++ = '=';
|
||||||
*p++ = '"';
|
*p++ = '"';
|
||||||
for (char c : labels[i].second) {
|
for (char c : value) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\\':
|
case '\\':
|
||||||
*p++ = '\\';
|
*p++ = '\\';
|
||||||
@@ -1261,9 +1278,45 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*p++ = '"';
|
*p++ = '"';
|
||||||
}
|
|
||||||
*p++ = '}';
|
*p++ = '}';
|
||||||
return std::string_view(buf, p - buf);
|
return std::string_view(buf, p - buf);
|
||||||
|
} else {
|
||||||
|
// Append to existing format: {existing,key="value"}
|
||||||
|
size_t required_size = base_format.length() + 1 +
|
||||||
|
key_value_size; // comma + key="value", replace }
|
||||||
|
char *buf = arena.allocate<char>(required_size);
|
||||||
|
char *p = buf;
|
||||||
|
// Copy everything except the closing }
|
||||||
|
std::memcpy(p, base_format.data(), base_format.length() - 1);
|
||||||
|
p += base_format.length() - 1;
|
||||||
|
*p++ = ',';
|
||||||
|
std::memcpy(p, key.data(), key.length());
|
||||||
|
p += key.length();
|
||||||
|
*p++ = '=';
|
||||||
|
*p++ = '"';
|
||||||
|
for (char c : value) {
|
||||||
|
switch (c) {
|
||||||
|
case '\\':
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = '\\';
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = '"';
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = 'n';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*p++ = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p++ = '"';
|
||||||
|
*p++ = '}';
|
||||||
|
return std::string_view(buf, p - buf);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Format counters - ITERATION ORDER MUST MATCH COMPUTE PHASE
|
// Format counters - ITERATION ORDER MUST MATCH COMPUTE PHASE
|
||||||
@@ -1276,21 +1329,13 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
|
|||||||
output.push_back(format(arena, "# TYPE %.*s counter\n",
|
output.push_back(format(arena, "# TYPE %.*s counter\n",
|
||||||
static_cast<int>(name.length()), name.data()));
|
static_cast<int>(name.length()), name.data()));
|
||||||
|
|
||||||
ArenaVector<std::pair<std::string_view, std::string_view>> labels_sv(
|
|
||||||
&arena);
|
|
||||||
|
|
||||||
// Format callback values
|
// Format callback values
|
||||||
for (const auto &[labels_key, callback] : family->callbacks) {
|
for (const auto &[labels_key, callback] : family->callbacks) {
|
||||||
auto value = next_value++->as_double;
|
auto value = next_value++->as_double;
|
||||||
labels_sv.clear();
|
output.push_back(format(
|
||||||
for (size_t i = 0; i < labels_key.labels.size(); ++i) {
|
arena, "%.*s%.*s %.17g\n", static_cast<int>(name.length()),
|
||||||
labels_sv.push_back(labels_key.labels[i]);
|
name.data(), static_cast<int>(labels_key.prometheus_format.length()),
|
||||||
}
|
labels_key.prometheus_format.data(), value));
|
||||||
auto labels = format_labels(labels_sv);
|
|
||||||
output.push_back(format(arena, "%.*s%.*s %.17g\n",
|
|
||||||
static_cast<int>(name.length()), name.data(),
|
|
||||||
static_cast<int>(labels.length()), labels.data(),
|
|
||||||
value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use pre-computed data (same as compute phase)
|
// Use pre-computed data (same as compute phase)
|
||||||
@@ -1299,15 +1344,11 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
|
|||||||
// Format counter values using pre-computed values
|
// Format counter values using pre-computed values
|
||||||
for (const auto &data : family_data) {
|
for (const auto &data : family_data) {
|
||||||
auto total_value = next_value++->as_double;
|
auto total_value = next_value++->as_double;
|
||||||
labels_sv.clear();
|
output.push_back(
|
||||||
for (size_t i = 0; i < data.labels_key.labels.size(); ++i) {
|
format(arena, "%.*s%.*s %.17g\n", static_cast<int>(name.length()),
|
||||||
labels_sv.push_back(data.labels_key.labels[i]);
|
name.data(),
|
||||||
}
|
static_cast<int>(data.labels_key.prometheus_format.length()),
|
||||||
auto labels = format_labels(labels_sv);
|
data.labels_key.prometheus_format.data(), total_value));
|
||||||
output.push_back(format(arena, "%.*s%.*s %.17g\n",
|
|
||||||
static_cast<int>(name.length()), name.data(),
|
|
||||||
static_cast<int>(labels.length()), labels.data(),
|
|
||||||
total_value));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1321,36 +1362,24 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
|
|||||||
output.push_back(format(arena, "# TYPE %.*s gauge\n",
|
output.push_back(format(arena, "# TYPE %.*s gauge\n",
|
||||||
static_cast<int>(name.length()), name.data()));
|
static_cast<int>(name.length()), name.data()));
|
||||||
|
|
||||||
ArenaVector<std::pair<std::string_view, std::string_view>> labels_sv(
|
|
||||||
&arena);
|
|
||||||
|
|
||||||
// Format callback values
|
// Format callback values
|
||||||
for (const auto &[labels_key, callback] : family->callbacks) {
|
for (const auto &[labels_key, callback] : family->callbacks) {
|
||||||
auto value = next_value++->as_double;
|
auto value = next_value++->as_double;
|
||||||
labels_sv.clear();
|
output.push_back(format(
|
||||||
for (size_t i = 0; i < labels_key.labels.size(); ++i) {
|
arena, "%.*s%.*s %.17g\n", static_cast<int>(name.length()),
|
||||||
labels_sv.push_back(labels_key.labels[i]);
|
name.data(), static_cast<int>(labels_key.prometheus_format.length()),
|
||||||
}
|
labels_key.prometheus_format.data(), value));
|
||||||
auto labels = format_labels(labels_sv);
|
|
||||||
output.push_back(format(arena, "%.*s%.*s %.17g\n",
|
|
||||||
static_cast<int>(name.length()), name.data(),
|
|
||||||
static_cast<int>(labels.length()), labels.data(),
|
|
||||||
value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use pre-computed data (same as compute phase)
|
// Use pre-computed data (same as compute phase)
|
||||||
const auto &family_data = label_sets.gauge_data[gauge_family_idx++];
|
const auto &family_data = label_sets.gauge_data[gauge_family_idx++];
|
||||||
for (const auto &data : family_data) {
|
for (const auto &data : family_data) {
|
||||||
auto value = next_value++->as_double;
|
auto value = next_value++->as_double;
|
||||||
labels_sv.clear();
|
output.push_back(
|
||||||
for (size_t i = 0; i < data.labels_key.labels.size(); ++i) {
|
format(arena, "%.*s%.*s %.17g\n", static_cast<int>(name.length()),
|
||||||
labels_sv.push_back(data.labels_key.labels[i]);
|
name.data(),
|
||||||
}
|
static_cast<int>(data.labels_key.prometheus_format.length()),
|
||||||
auto labels = format_labels(labels_sv);
|
data.labels_key.prometheus_format.data(), value));
|
||||||
output.push_back(format(arena, "%.*s%.*s %.17g\n",
|
|
||||||
static_cast<int>(name.length()), name.data(),
|
|
||||||
static_cast<int>(labels.length()), labels.data(),
|
|
||||||
value));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1367,9 +1396,6 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
|
|||||||
// Use pre-computed data (same as compute phase)
|
// Use pre-computed data (same as compute phase)
|
||||||
const auto &family_data = label_sets.histogram_data[histogram_family_idx++];
|
const auto &family_data = label_sets.histogram_data[histogram_family_idx++];
|
||||||
|
|
||||||
ArenaVector<std::pair<std::string_view, std::string_view>> bucket_labels_sv(
|
|
||||||
&arena);
|
|
||||||
|
|
||||||
// Format histogram data using pre-computed values
|
// Format histogram data using pre-computed values
|
||||||
for (const auto &data : family_data) {
|
for (const auto &data : family_data) {
|
||||||
// Get bucket count from pre-computed data
|
// Get bucket count from pre-computed data
|
||||||
@@ -1378,13 +1404,9 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
|
|||||||
// Format explicit bucket counts
|
// Format explicit bucket counts
|
||||||
for (size_t i = 0; i < bucket_count; ++i) {
|
for (size_t i = 0; i < bucket_count; ++i) {
|
||||||
auto count = next_value++->as_uint64;
|
auto count = next_value++->as_uint64;
|
||||||
bucket_labels_sv.clear();
|
auto bucket_value = static_format(arena, family->buckets[i]);
|
||||||
for (size_t j = 0; j < data.labels_key.labels.size(); ++j) {
|
auto labels = append_label_to_format(data.labels_key.prometheus_format,
|
||||||
bucket_labels_sv.push_back(data.labels_key.labels[j]);
|
"le", bucket_value);
|
||||||
}
|
|
||||||
bucket_labels_sv.push_back(
|
|
||||||
{"le", static_format(arena, family->buckets[i])});
|
|
||||||
auto labels = format_labels(bucket_labels_sv);
|
|
||||||
output.push_back(format(
|
output.push_back(format(
|
||||||
arena, "%.*s_bucket%.*s %llu\n", static_cast<int>(name.length()),
|
arena, "%.*s_bucket%.*s %llu\n", static_cast<int>(name.length()),
|
||||||
name.data(), static_cast<int>(labels.length()), labels.data(),
|
name.data(), static_cast<int>(labels.length()), labels.data(),
|
||||||
@@ -1393,12 +1415,8 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
|
|||||||
|
|
||||||
// Format +Inf bucket
|
// Format +Inf bucket
|
||||||
auto observations = next_value++->as_uint64;
|
auto observations = next_value++->as_uint64;
|
||||||
bucket_labels_sv.clear();
|
auto inf_labels = append_label_to_format(
|
||||||
for (size_t j = 0; j < data.labels_key.labels.size(); ++j) {
|
data.labels_key.prometheus_format, "le", "+Inf");
|
||||||
bucket_labels_sv.push_back(data.labels_key.labels[j]);
|
|
||||||
}
|
|
||||||
bucket_labels_sv.push_back({"le", "+Inf"});
|
|
||||||
auto inf_labels = format_labels(bucket_labels_sv);
|
|
||||||
output.push_back(format(
|
output.push_back(format(
|
||||||
arena, "%.*s_bucket%.*s %llu\n", static_cast<int>(name.length()),
|
arena, "%.*s_bucket%.*s %llu\n", static_cast<int>(name.length()),
|
||||||
name.data(), static_cast<int>(inf_labels.length()), inf_labels.data(),
|
name.data(), static_cast<int>(inf_labels.length()), inf_labels.data(),
|
||||||
@@ -1406,20 +1424,19 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
|
|||||||
|
|
||||||
// Format sum
|
// Format sum
|
||||||
auto sum = next_value++->as_double;
|
auto sum = next_value++->as_double;
|
||||||
bucket_labels_sv.clear();
|
output.push_back(
|
||||||
for (size_t j = 0; j < data.labels_key.labels.size(); ++j) {
|
format(arena, "%.*s_sum%.*s %.17g\n", static_cast<int>(name.length()),
|
||||||
bucket_labels_sv.push_back(data.labels_key.labels[j]);
|
name.data(),
|
||||||
}
|
static_cast<int>(data.labels_key.prometheus_format.length()),
|
||||||
auto labels = format_labels(bucket_labels_sv);
|
data.labels_key.prometheus_format.data(), sum));
|
||||||
output.push_back(format(
|
|
||||||
arena, "%.*s_sum%.*s %.17g\n", static_cast<int>(name.length()),
|
|
||||||
name.data(), static_cast<int>(labels.length()), labels.data(), sum));
|
|
||||||
|
|
||||||
// Format count
|
// Format count
|
||||||
auto count = next_value++->as_uint64;
|
auto count = next_value++->as_uint64;
|
||||||
output.push_back(format(arena, "%.*s_count%.*s %llu\n",
|
output.push_back(
|
||||||
|
format(arena, "%.*s_count%.*s %llu\n",
|
||||||
static_cast<int>(name.length()), name.data(),
|
static_cast<int>(name.length()), name.data(),
|
||||||
static_cast<int>(labels.length()), labels.data(),
|
static_cast<int>(data.labels_key.prometheus_format.length()),
|
||||||
|
data.labels_key.prometheus_format.data(),
|
||||||
static_cast<unsigned long long>(count)));
|
static_cast<unsigned long long>(count)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1437,16 +1454,17 @@ void Family<Counter>::register_callback(
|
|||||||
|
|
||||||
// Validate that labels aren't already in use by create() calls
|
// Validate that labels aren't already in use by create() calls
|
||||||
for (const auto &[thread_id, per_thread] : p->per_thread_state) {
|
for (const auto &[thread_id, per_thread] : p->per_thread_state) {
|
||||||
validate_or_abort(per_thread.instances.find(key) ==
|
validate_or_abort(
|
||||||
per_thread.instances.end(),
|
per_thread.instances.find(key) == per_thread.instances.end(),
|
||||||
"labels already registered as static instance",
|
"labels already registered as static instance",
|
||||||
key.labels.empty() ? "(no labels)" : key.labels[0].first);
|
key.prometheus_format.empty() ? "(no labels)" : key.prometheus_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate that callback isn't already registered for these labels
|
// Validate that callback isn't already registered for these labels
|
||||||
validate_or_abort(p->callbacks.find(key) == p->callbacks.end(),
|
validate_or_abort(p->callbacks.find(key) == p->callbacks.end(),
|
||||||
"callback already registered for labels",
|
"callback already registered for labels",
|
||||||
key.labels.empty() ? "(no labels)" : key.labels[0].first);
|
key.prometheus_format.empty() ? "(no labels)"
|
||||||
|
: key.prometheus_format);
|
||||||
|
|
||||||
p->callbacks[std::move(key)] = std::move(callback);
|
p->callbacks[std::move(key)] = std::move(callback);
|
||||||
}
|
}
|
||||||
@@ -1461,12 +1479,14 @@ void Family<Gauge>::register_callback(
|
|||||||
// Validate that labels aren't already in use by create() calls
|
// Validate that labels aren't already in use by create() calls
|
||||||
validate_or_abort(p->instances.find(key) == p->instances.end(),
|
validate_or_abort(p->instances.find(key) == p->instances.end(),
|
||||||
"labels already registered as static instance",
|
"labels already registered as static instance",
|
||||||
key.labels.empty() ? "(no labels)" : key.labels[0].first);
|
key.prometheus_format.empty() ? "(no labels)"
|
||||||
|
: key.prometheus_format);
|
||||||
|
|
||||||
// Validate that callback isn't already registered for these labels
|
// Validate that callback isn't already registered for these labels
|
||||||
validate_or_abort(p->callbacks.find(key) == p->callbacks.end(),
|
validate_or_abort(p->callbacks.find(key) == p->callbacks.end(),
|
||||||
"callback already registered for labels",
|
"callback already registered for labels",
|
||||||
key.labels.empty() ? "(no labels)" : key.labels[0].first);
|
key.prometheus_format.empty() ? "(no labels)"
|
||||||
|
: key.prometheus_format);
|
||||||
|
|
||||||
p->callbacks[std::move(key)] = std::move(callback);
|
p->callbacks[std::move(key)] = std::move(callback);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user