Seastar
High performance C++ framework for concurrent servers
metrics.hh
Go to the documentation of this file.
1 /*
2  * This file is open source software, licensed to you under the terms
3  * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4  * distributed with this work for additional information regarding copyright
5  * ownership. You may not use this file except in compliance with the License.
6  *
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an
13  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14  * KIND, either express or implied. See the License for the
15  * specific language governing permissions and limitations
16  * under the License.
17  */
18 /*
19  * Copyright (C) 2016 ScyllaDB.
20  */
21 
22 #pragma once
23 
24 #ifndef SEASTAR_MODULE
25 #include <functional>
26 #include <limits>
27 #include <map>
28 #include <type_traits>
29 #include <variant>
30 #include <fmt/format.h>
31 #endif
32 #include "future.hh"
33 #include <seastar/core/sstring.hh>
34 #include <seastar/core/shared_ptr.hh>
36 #include <seastar/core/metrics_types.hh>
37 #include <seastar/util/std-compat.hh>
38 #include <seastar/util/bool_class.hh>
39 #include <seastar/util/modules.hh>
40 
52 namespace seastar {
53 
99 namespace metrics {
100 
101 SEASTAR_MODULE_EXPORT_BEGIN
102 
103 class double_registration : public std::runtime_error {
104 public:
105  double_registration(std::string what);
106 };
107 
114 using metric_type_def = sstring;
115 using metric_name_type = sstring;
116 using instance_id_type = sstring;
118 
134 class description {
135 public:
136  description(sstring s = sstring()) : _s(std::move(s))
137  {}
138  const sstring& str() const {
139  return _s;
140  }
141 private:
142  sstring _s;
143 };
144 
163  sstring _key;
164  sstring _value;
165 public:
178  template<typename T>
179  label_instance(const sstring& key, T v) : _key(key), _value(fmt::to_string(v)){}
180 
184  const sstring key() const {
185  return _key;
186  }
187 
191  const sstring value() const {
192  return _value;
193  }
194  bool operator<(const label_instance&) const;
195  bool operator==(const label_instance&) const;
196  bool operator!=(const label_instance&) const;
197 };
198 
199 
217 class label {
218  sstring key;
219 public:
220  using instance = label_instance;
226  explicit label(const sstring& key) : key(key) {
227  }
228 
241  template<typename T>
242  instance operator()(T value) const {
243  return label_instance(key, std::forward<T>(value));
244  }
245 
249  const sstring& name() const {
250  return key;
251  }
252 };
253 SEASTAR_MODULE_EXPORT_END
254 
262 namespace impl {
263 
264 // The value binding data types
265 enum class data_type : uint8_t {
266  COUNTER,
267  REAL_COUNTER,
268  GAUGE,
269  HISTOGRAM,
270  SUMMARY,
271 };
272 
273 template <bool callable, typename T>
275  using type = T;
276 };
277 
278 template <typename T>
279 struct real_counter_type_traits<true, T> {
280  using type = std::invoke_result_t<T>;
281 };
282 
283 template <typename T>
286  static constexpr bool is_integral = std::is_integral_v<typename real_traits::type>;
287  static constexpr data_type type = is_integral ? data_type::COUNTER : data_type::REAL_COUNTER;
288 };
289 
296 public:
297  std::variant<double, histogram> u;
298  data_type _type;
299  data_type type() const {
300  return _type;
301  }
302 
303  double d() const {
304  return std::get<double>(u);
305  }
306 
307  uint64_t ui() const {
308  auto d = std::get<double>(u);
309  if (d >= 0 && d <= double(std::numeric_limits<long>::max())) {
310  return lround(d);
311  } else {
312  // double value is out of range or NaN or Inf
313  ulong_conversion_error(d);
314  return 0;
315  }
316  }
317 
318  int64_t i() const {
319  auto d = std::get<double>(u);
320  if (d >= double(std::numeric_limits<long>::min()) && d <= double(std::numeric_limits<long>::max())) {
321  return lround(d);
322  } else {
323  // double value is out of range or NaN or Inf
324  ulong_conversion_error(d);
325  return 0;
326  }
327  }
328 
329  metric_value()
330  : _type(data_type::GAUGE) {
331  }
332 
333  metric_value(histogram&& h, data_type t = data_type::HISTOGRAM) :
334  u(std::move(h)), _type(t) {
335  }
336  metric_value(const histogram& h, data_type t = data_type::HISTOGRAM) :
337  u(h), _type(t) {
338  }
339 
340  metric_value(double d, data_type t)
341  : u(d), _type(t) {
342  }
343 
344  metric_value& operator+=(const metric_value& c) {
345  *this = *this + c;
346  return *this;
347  }
348 
349  metric_value operator+(const metric_value& c);
350  const histogram& get_histogram() const {
351  return std::get<histogram>(u);
352  }
353 
360  bool is_empty() const noexcept {
361  return ((_type == data_type::HISTOGRAM || _type == data_type::SUMMARY) && get_histogram().sample_count == 0) ||
362  ((_type == data_type::COUNTER || _type == data_type::REAL_COUNTER) && d() == 0);
363  }
364 private:
365  static void ulong_conversion_error(double d);
366 };
367 
368 using metric_function = std::function<metric_value()>;
369 
370 struct metric_type {
371  data_type base_type;
372  metric_type_def type_name;
373 };
374 
376  metric_name_type name;
377  metric_type type;
378  metric_function f;
379  description d;
380  bool enabled = true;
381  skip_when_empty _skip_when_empty = skip_when_empty::no;
382  std::vector<std::string> aggregate_labels;
383  std::map<sstring, sstring> labels;
384  metric_definition_impl& operator ()(bool enabled);
385  metric_definition_impl& operator ()(const label_instance& label);
386  metric_definition_impl& operator ()(skip_when_empty skip) noexcept;
387  metric_definition_impl& aggregate(const std::vector<label>& labels) noexcept;
388  metric_definition_impl& set_skip_when_empty(bool skip=true) noexcept;
389  metric_definition_impl& set_type(const sstring& type_name);
391  metric_name_type name,
392  metric_type type,
393  metric_function f,
394  description d,
395  std::vector<label_instance> labels,
396  std::vector<label> aggregate_labels = {});
397 };
398 
400 public:
401  metric_groups_def() = default;
402  virtual ~metric_groups_def() = default;
403  metric_groups_def(const metric_groups_def&) = delete;
405  virtual metric_groups_def& add_metric(group_name_type name, const metric_definition& md) = 0;
406  virtual metric_groups_def& add_group(group_name_type name, const std::initializer_list<metric_definition>& l) = 0;
407  virtual metric_groups_def& add_group(group_name_type name, const std::vector<metric_definition>& l) = 0;
408 };
409 
410 instance_id_type shard();
411 
412 template<typename T, typename = std::enable_if_t<std::is_invocable_v<T>>>
413 metric_function make_function(T val, data_type dt) {
414  return [dt, val = std::move(val)] {
415  return metric_value(val(), dt);
416  };
417 }
418 
419 template<typename T, typename = std::enable_if_t<!std::is_invocable_v<T>>>
420 metric_function make_function(T& val, data_type dt) {
421  return [dt, &val] {
422  return metric_value(val, dt);
423  };
424 }
425 }
426 
427 extern const bool metric_disabled;
428 
429 extern label shard_label;
430 
431 /*
432  * The metrics definition are defined to be compatible with collectd metrics defintion.
433  * Typically you should used gauge or derived.
434  */
435 
436 
442 template<typename T>
444  T&& val, description d = description(), std::vector<label_instance> labels = {}) {
445  return {name, {impl::data_type::GAUGE, "gauge"}, make_function(std::forward<T>(val), impl::data_type::GAUGE), d, labels};
446 }
447 
453 template<typename T>
455  description d, T&& val) {
456  return {name, {impl::data_type::GAUGE, "gauge"}, make_function(std::forward<T>(val), impl::data_type::GAUGE), d, {}};
457 }
458 
464 template<typename T>
466  description d, std::vector<label_instance> labels, T&& val) {
467  return {name, {impl::data_type::GAUGE, "gauge"}, make_function(std::forward<T>(val), impl::data_type::GAUGE), d, labels};
468 }
469 
470 
479 template<typename T>
480 [[deprecated("Use make_counter()")]]
482  T&& val, description d = description(), std::vector<label_instance> labels = {}) {
483  return make_counter(std::move(name), std::forward<T>(val), std::move(d), std::move(labels));
484 }
485 
486 
495 template<typename T>
496 [[deprecated("Use make_counter()")]]
498  T&& val) {
499  return make_counter(std::move(name), std::forward<T>(val), std::move(d), {});
500 }
501 
502 
511 template<typename T>
512 [[deprecated("Use make_counter()")]]
513 impl::metric_definition_impl make_derive(metric_name_type name, description d, std::vector<label_instance> labels,
514  T&& val) {
515  return make_counter(std::move(name), std::forward<T>(val), std::move(d), std::move(labels));
516 }
517 
518 
528 template<typename T>
530  T&& val, description d = description(), std::vector<label_instance> labels = {}) {
531  auto type = impl::counter_type_traits<std::remove_reference_t<T>>::type;
532  return {name, {type, "counter"}, make_function(std::forward<T>(val), type), d, labels};
533 }
534 
544 template<typename T>
546  return make_counter(std::move(name), std::forward<T>(val), std::move(d), {});
547 }
548 
558 template<typename T>
559 impl::metric_definition_impl make_counter(metric_name_type name, description d, std::vector<label_instance> labels, T&& val) {
560  return make_counter(std::move(name), std::forward<T>(val), std::move(d), std::move(labels));
561 }
562 
569 template<typename T>
570 [[deprecated("Use make_counter()")]]
572  T&& val, description d = description(), std::vector<label_instance> labels = {}) {
573  return make_counter(std::move(name), std::forward<T>(val), std::move(d), std::move(labels));
574 }
575 
582 template<typename T>
584  T&& val, description d = description(), std::vector<label_instance> labels = {}) {
585  return {name, {impl::data_type::HISTOGRAM, "histogram"}, make_function(std::forward<T>(val), impl::data_type::HISTOGRAM), d, labels};
586 }
587 
594 template<typename T>
596  description d, std::vector<label_instance> labels, T&& val) {
597  return {name, {impl::data_type::HISTOGRAM, "histogram"}, make_function(std::forward<T>(val), impl::data_type::HISTOGRAM), d, labels};
598 }
599 
600 
607 template<typename T>
609  description d, T&& val) {
610  return {name, {impl::data_type::HISTOGRAM, "histogram"}, make_function(std::forward<T>(val), impl::data_type::HISTOGRAM), d, {}};
611 }
612 
619 template<typename T>
621  description d, T&& val) {
622  return {name, {impl::data_type::SUMMARY, "summary"}, make_function(std::forward<T>(val), impl::data_type::SUMMARY), d, {}};
623 }
624 
625 
633 template<typename T>
635  T&& val, description d = description(), std::vector<label_instance> labels = {},
636  instance_id_type = impl::shard()) {
637  return make_counter(name, std::forward<T>(val), d, labels).set_type("total_bytes");
638 }
639 
647 template<typename T>
649  T&& val, description d = description(), std::vector<label_instance> labels = {},
650  instance_id_type = impl::shard()) {
651  return make_gauge(name, std::forward<T>(val), d, labels).set_type("bytes");
652 }
653 
654 
661 template<typename T>
663  T&& val, description d = description(), std::vector<label_instance> labels = {},
664  instance_id_type = impl::shard()) {
665  return make_gauge(name, std::forward<T>(val), d, labels).set_type("queue_length");
666 }
667 
668 
675 template<typename T>
677  T&& val, description d = description(), std::vector<label_instance> labels = {},
678  instance_id_type = impl::shard()) {
679  return make_counter(name, std::forward<T>(val), d, labels).set_type("total_operations");
680 }
681 
683 }
684 }
Human-readable description of a metric/group.
Definition: metrics.hh:134
Definition: metrics.hh:103
A helper class that used to return metrics value.
Definition: metrics.hh:295
bool is_empty() const noexcept
return true if this metric was never used
Definition: metrics.hh:360
Label a metrics.
Definition: metrics.hh:162
const sstring key() const
returns the label key
Definition: metrics.hh:184
label_instance(const sstring &key, T v)
create a label_instance label instance consists of key and value. The key is an sstring....
Definition: metrics.hh:179
const sstring value() const
returns the label value
Definition: metrics.hh:191
Class that creates label instances.
Definition: metrics.hh:217
instance operator()(T value) const
creating a label instance
Definition: metrics.hh:242
label(const sstring &key)
creating a label key is the label name, it will be the key for all label_instance that will be create...
Definition: metrics.hh:226
const sstring & name() const
returns the label name
Definition: metrics.hh:249
Definition: metrics_registration.hh:67
impl::metric_definition_impl make_queue_length(metric_name_type name, T &&val, description d=description(), std::vector< label_instance > labels={}, instance_id_type=impl::shard())
create a queue_length metric.
Definition: metrics.hh:662
sstring metric_type_def
Definition: metrics.hh:114
sstring metric_name_type
Definition: metrics.hh:115
impl::metric_definition_impl make_total_operations(metric_name_type name, T &&val, description d=description(), std::vector< label_instance > labels={}, instance_id_type=impl::shard())
create a total operation metric.
Definition: metrics.hh:676
sstring instance_id_type
Definition: metrics.hh:116
impl::metric_definition_impl make_total_bytes(metric_name_type name, T &&val, description d=description(), std::vector< label_instance > labels={}, instance_id_type=impl::shard())
create a total_bytes metric.
Definition: metrics.hh:634
impl::metric_definition_impl make_derive(metric_name_type name, T &&val, description d=description(), std::vector< label_instance > labels={})
Derive are used when a rate is more interesting than the value.
Definition: metrics.hh:481
impl::metric_definition_impl make_current_bytes(metric_name_type name, T &&val, description d=description(), std::vector< label_instance > labels={}, instance_id_type=impl::shard())
create a current_bytes metric.
Definition: metrics.hh:648
impl::metric_definition_impl make_summary(metric_name_type name, description d, T &&val)
create a summary metric.
Definition: metrics.hh:620
impl::metric_definition_impl make_gauge(metric_name_type name, T &&val, description d=description(), std::vector< label_instance > labels={})
Gauge are a general purpose metric.
Definition: metrics.hh:443
impl::metric_definition_impl make_absolute(metric_name_type name, T &&val, description d=description(), std::vector< label_instance > labels={})
create an absolute metric.
Definition: metrics.hh:571
impl::metric_definition_impl make_counter(metric_name_type name, T &&val, description d=description(), std::vector< label_instance > labels={})
create a counter metric
Definition: metrics.hh:529
impl::metric_definition_impl make_histogram(metric_name_type name, T &&val, description d=description(), std::vector< label_instance > labels={})
create a histogram metric.
Definition: metrics.hh:583
holds the metric_groups definition needed by class that reports metrics
holds the implementation parts of the metrics layer, do not use directly.
sstring group_name_type
Definition: metrics_registration.hh:64
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
Histogram data type.
Definition: metrics_types.hh:54
Definition: metrics.hh:370