+void write_histogram(std::stringstream& s, const config& ctx, const sstring& name, const seastar::metrics::histogram& h, std::map<sstring, sstring> labels) noexcept {
+ add_name(s, name + "_sum", labels, ctx);
+ s << h.sample_sum << '\n';
+
+ add_name(s, name + "_count", labels, ctx);
+ s << h.sample_count << '\n';
+
+ auto& le = labels["le"];
+ auto bucket = name + "_bucket";
+ for (auto i : h.buckets) {
+ le = std::to_string(i.upper_bound);
+ add_name(s, bucket, labels, ctx);
+ s << i.count << '\n';
+ }
+ labels["le"] = "+Inf";
+ add_name(s, bucket, labels, ctx);
+ s << h.sample_count << '\n';
+}
+
+void write_summary(std::stringstream& s, const config& ctx, const sstring& name, const seastar::metrics::histogram& h, std::map<sstring, sstring> labels) noexcept {
+ if (h.sample_sum) {
+ add_name(s, name + "_sum", labels, ctx);
+ s << h.sample_sum << '\n';
+ }
+ if (h.sample_count) {
+ add_name(s, name + "_count", labels, ctx);
+ s << h.sample_count << '\n';
+ }
+ auto& le = labels["quantile"];
+ for (auto i : h.buckets) {
+ le = std::to_string(i.upper_bound);
+ add_name(s, name, labels, ctx);
+ s << i.count << '\n';
+ }
+}
+/*!
+ * \brief a helper class to aggregate metrics over labels
+ *
+ * This class sum multiple metrics based on a list of labels.
+ * It returns one or more metrics each aggregated by the aggregate_by labels.
+ *
+ * To use it, you define what labels it should aggregate by and then pass to
+ * it metrics with their labels.
+ * For example if a metrics has a 'shard' and 'name' labels and you aggregate by 'shard'
+ * it would return a map of metrics each with only the 'name' label
+ *
+ */
+class metric_aggregate_by_labels {
+ std::vector<std::string> _labels_to_aggregate_by;
+ std::unordered_map<std::map<sstring, sstring>, seastar::metrics::impl::metric_value> _values;
+public:
+ metric_aggregate_by_labels(std::vector<std::string> labels) : _labels_to_aggregate_by(std::move(labels)) {
+ }
+ /*!
+ * \brief add a metric
+ *
+ * This method gets a metric and its labels and adds it to the aggregated metric.
+ * For example, if a metric has the labels {'shard':'0', 'name':'myhist'} and we are aggregating
+ * over 'shard'
+ * The metric would be added to the aggregated metric with labels {'name':'myhist'}.
+ *
+ */
+ void add(const seastar::metrics::impl::metric_value& m, std::map<sstring, sstring> labels) noexcept {
+ for (auto&& l : _labels_to_aggregate_by) {
+ labels.erase(l);
+ }
+ std::unordered_map<std::map<sstring, sstring>, seastar::metrics::impl::metric_value>::iterator i = _values.find(labels);
+ if ( i == _values.end()) {
+ _values.emplace(std::move(labels), m);
+ } else {
+ i->second += m;
+ }
+ }
+ const std::unordered_map<std::map<sstring, sstring>, seastar::metrics::impl::metric_value>& get_values() const noexcept {
+ return _values;
+ }
+ bool empty() const noexcept {
+ return _values.empty();
+ }
+};
+
+std::string get_value_as_string(std::stringstream& s, const mi::metric_value& value) noexcept {
+ std::string value_str;
+ try {
+ value_str = to_str(value);
+ } catch (const std::range_error& e) {
+ seastar_logger.debug("prometheus: get_value_as_string: {}: {}", s.str(), e.what());
+ value_str = "NaN";
+ } catch (...) {
+ auto ex = std::current_exception();
+ // print this error as it's ignored later on by `connection::start_response`
+ seastar_logger.error("prometheus: get_value_as_string: {}: {}", s.str(), ex);
+ std::rethrow_exception(std::move(ex));
+ }
+ return value_str;
+}
+
+future<> write_text_representation(output_stream<char>& out, const config& ctx, const metric_family_range& m, bool show_help, std::function<bool(const mi::labels_type&)> filter) {
+ return seastar::async([&ctx, &out, &m, show_help, filter] () mutable {