/* * This file is open source software, licensed to you under the terms * of the Apache License, Version 2.0 (the "License"). See the NOTICE file * distributed with this work for additional information regarding copyright * ownership. You may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* * Copyright (C) 2024 ScyllaDB */ #include #include #include #include #include #include #include #include "../../apps/lib/stop_signal.hh" #include #include #include using namespace seastar; using namespace std::chrono_literals; namespace sm = seastar::metrics; struct serializer {}; struct metric_def { sstring name; sstring type; std::vector values; std::vector labels; }; struct config { std::vector metrics; std::vector metric_family_config; }; namespace YAML { template<> struct convert { static bool decode(const Node& node, metric_def& cfg) { if (node["name"]) { cfg.name = node["name"].as(); } if (node["type"]) { cfg.type = node["type"].as(); } if (node["values"]) { cfg.values = node["values"].as>(); } if (node["labels"]) { const auto labels = node["labels"].as>(); for (auto& [key, value]: labels) { cfg.labels.emplace_back(key, value); } } return true; } }; template<> struct convert { static bool decode(const Node& node, sm::metric_family_config& cfg) { if (node["name"]) { cfg.name = node["name"].as(); } if (node["regex_name"]) { cfg.regex_name = node["regex_name"].as(); } if (node["aggregate_labels"]) { cfg.aggregate_labels = node["aggregate_labels"].as>(); } return true; } }; template<> struct convert { static bool decode(const Node& node, config& cfg) { if (node["metrics"]) { cfg.metrics = node["metrics"].as>(); } if (node["metric_family_config"]) { cfg.metric_family_config = node["metric_family_config"].as>(); } return true; } }; } std::function make_histogram_fun(const metric_def& c) { sm::internal::time_estimated_histogram histogram; for (const auto& v : c.values) { histogram.add_micro(v); } return [histogram]() {return histogram;}; } sm::impl::metric_definition_impl make_metrics_definition(const metric_def& jc) { if (jc.type == "histogram") { sm::internal::time_estimated_histogram histogram; for (const auto& v : jc.values) { histogram.add_micro(v); } return sm::make_histogram(jc.name, [histogram]() {return histogram.to_metrics_histogram();}, sm::description(jc.name), jc.labels ); } if (jc.type == "gauge") { return sm::make_gauge(jc.name, [val=jc.values[0]] { return val; }, sm::description(jc.name), jc.labels ); } return sm::make_counter(jc.name, [val=jc.values[0]] { return val; }, sm::description(jc.name), jc.labels ); } int main(int ac, char** av) { namespace bpo = boost::program_options; app_template app; auto opt_add = app.add_options(); opt_add ("listen", bpo::value()->default_value("0.0.0.0"), "address to start Prometheus server on") ("port", bpo::value()->default_value(9180), "Prometheus port") ("conf", bpo::value()->default_value("./conf.yaml"), "config with jobs and options") ; httpd::http_server_control prometheus_server; return app.run(ac, av, [&] { return seastar::async([&] { sm::metric_groups _metrics; seastar_apps_lib::stop_signal stop_signal; auto& opts = app.configuration(); auto& listen = opts["listen"].as(); auto& port = opts["port"].as(); auto& conf = opts["conf"].as(); YAML::Node doc = YAML::LoadFile(conf); auto cfg = doc.as(); for (auto&& jc : cfg.metrics) { _metrics.add_group("test_group", { make_metrics_definition(jc) }); } smp::invoke_on_all([] { std::vector rl(2); rl[0].source_labels = {"__name__"}; rl[0].expr = ".*"; rl[0].action = metrics::relabel_config::relabel_action::drop; rl[1].source_labels = {"private"}; rl[1].expr = ".*"; rl[1].action = metrics::relabel_config::relabel_action::keep; return metrics::set_relabel_configs(rl).then([](metrics::metric_relabeling_result) { return; }); }).get(); if (!cfg.metric_family_config.empty()) { sm::set_metric_family_configs(cfg.metric_family_config); } prometheus_server.start("prometheus").get(); auto stop_server = deferred_stop(prometheus_server); prometheus::config pctx; pctx.allow_protobuf = true; prometheus::start(prometheus_server, pctx).get(); prometheus_server.listen(socket_address{listen, port}).handle_exception([] (auto ep) { return make_exception_future<>(ep); }).get(); fmt::print("{}\n", port); fflush(stdout); stop_signal.wait().get(); }); }); }