Fix static initialization order fiasco

This commit is contained in:
2025-08-30 17:57:16 -04:00
parent affeeb674a
commit 0ff197d406

View File

@@ -23,8 +23,6 @@
#include "format.hpp"
// TODO fix static initialization order fiasco
// Verify that malloc provides sufficient alignment for atomic 128-bit
// operations
static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= 16,
@@ -193,15 +191,27 @@ struct Histogram::State {
struct Metric {
static std::mutex mutex;
// Two-level map: name -> Family
static std::unordered_map<std::string,
std::unique_ptr<Family<Counter>::State>>
counterFamilies;
static std::unordered_map<std::string, std::unique_ptr<Family<Gauge>::State>>
gaugeFamilies;
static std::unordered_map<std::string,
std::unique_ptr<Family<Histogram>::State>>
histogramFamilies;
// Function-local statics to avoid static initialization order fiasco
static auto &get_counter_families() {
static std::unordered_map<std::string,
std::unique_ptr<Family<Counter>::State>>
counterFamilies;
return counterFamilies;
}
static auto &get_gauge_families() {
static std::unordered_map<std::string,
std::unique_ptr<Family<Gauge>::State>>
gaugeFamilies;
return gaugeFamilies;
}
static auto &get_histogram_families() {
static std::unordered_map<std::string,
std::unique_ptr<Family<Histogram>::State>>
histogramFamilies;
return histogramFamilies;
}
// Thread cleanup for per-family thread-local storage
struct ThreadInit {
@@ -214,7 +224,7 @@ struct Metric {
auto thread_id = std::this_thread::get_id();
// Accumulate counter families
for (auto &[name, family] : counterFamilies) {
for (auto &[name, family] : Metric::get_counter_families()) {
auto thread_it = family->perThreadState.find(thread_id);
if (thread_it != family->perThreadState.end()) {
for (auto &[labels_key, instance] : thread_it->second.instances) {
@@ -236,7 +246,7 @@ struct Metric {
}
// Accumulate histogram families
for (auto &[name, family] : histogramFamilies) {
for (auto &[name, family] : Metric::get_histogram_families()) {
auto thread_it = family->perThreadState.find(thread_id);
if (thread_it != family->perThreadState.end()) {
for (auto &[labels_key, instance] : thread_it->second.instances) {
@@ -490,7 +500,7 @@ Family<Counter> create_counter(std::string name, std::string help) {
name.c_str());
std::unique_lock<std::mutex> _{Metric::mutex};
auto &familyPtr = Metric::counterFamilies[name];
auto &familyPtr = Metric::get_counter_families()[name];
if (!familyPtr) {
familyPtr = std::make_unique<Family<Counter>::State>();
familyPtr->name = std::move(name);
@@ -511,7 +521,7 @@ Family<Gauge> create_gauge(std::string name, std::string help) {
name.c_str());
std::unique_lock<std::mutex> _{Metric::mutex};
auto &familyPtr = Metric::gaugeFamilies[name];
auto &familyPtr = Metric::get_gauge_families()[name];
if (!familyPtr) {
familyPtr = std::make_unique<Family<Gauge>::State>();
familyPtr->name = std::move(name);
@@ -533,7 +543,7 @@ Family<Histogram> create_histogram(std::string name, std::string help,
name.c_str());
std::unique_lock<std::mutex> _{Metric::mutex};
auto &familyPtr = Metric::histogramFamilies[name];
auto &familyPtr = Metric::get_histogram_families()[name];
if (!familyPtr) {
familyPtr = std::make_unique<Family<Histogram>::State>();
familyPtr->name = std::move(name);
@@ -724,7 +734,7 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
};
// Render counters
for (const auto &[name, family] : Metric::counterFamilies) {
for (const auto &[name, family] : Metric::get_counter_families()) {
output.push_back(
format(arena, "# HELP %s %s\n", name.c_str(), family->help.c_str()));
output.push_back(format(arena, "# TYPE %s counter\n", name.c_str()));
@@ -777,7 +787,7 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
}
// Render gauges
for (const auto &[name, family] : Metric::gaugeFamilies) {
for (const auto &[name, family] : Metric::get_gauge_families()) {
output.push_back(
format(arena, "# HELP %s %s\n", name.c_str(), family->help.c_str()));
output.push_back(format(arena, "# TYPE %s gauge\n", name.c_str()));
@@ -810,7 +820,7 @@ std::span<std::string_view> render(ArenaAllocator &arena) {
}
// Render histograms
for (const auto &[name, family] : Metric::histogramFamilies) {
for (const auto &[name, family] : Metric::get_histogram_families()) {
output.push_back(
format(arena, "# HELP %s %s\n", name.c_str(), family->help.c_str()));
output.push_back(format(arena, "# TYPE %s histogram\n", name.c_str()));
@@ -995,12 +1005,6 @@ void Family<Gauge>::register_callback(
// Static member definitions
std::mutex Metric::mutex;
std::unordered_map<std::string, std::unique_ptr<Family<Counter>::State>>
Metric::counterFamilies;
std::unordered_map<std::string, std::unique_ptr<Family<Gauge>::State>>
Metric::gaugeFamilies;
std::unordered_map<std::string, std::unique_ptr<Family<Histogram>::State>>
Metric::histogramFamilies;
thread_local Metric::ThreadInit Metric::thread_init;
} // namespace metric