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.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Copyright (C) 2016 ScyllaDB.
25 #include <seastar/core/sstring.hh>
26 #include <seastar/core/shared_ptr.hh>
27 #include <seastar/core/metrics_registration.hh>
28 #include <boost/lexical_cast.hpp>
30 #include <seastar/core/metrics_types.hh>
31 #include <seastar/util/std-compat.hh>
34 * \brief header for metrics creation.
36 * This header file contains the metrics creation method with their helper function.
37 * Include this file when need to create metrics.
38 * Typically this will be in your source file.
40 * Code that is under the impl namespace should not be used directly.
47 * \namespace seastar::metrics
48 * \brief metrics creation and registration
50 * the metrics namespace holds the relevant method and classes to generate metrics.
52 * The metrics layer support registering metrics, that later will be
53 * exported via different API protocols.
55 * To be able to support multiple protocols the following simplifications where made:
56 * 1. The id of the metrics is based on the collectd id
57 * 2. A metric could be a single value either a reference or a function
59 * To add metrics definition to class A do the following:
60 * * Add a metrics_group memeber to A
61 * * Add a a set_metrics() method that would be called in the constructor.
66 * #include "core/metrics_registration.hh"
68 * metric_groups _metrics
70 * void setup_metrics();
78 * include "core/metrics.hh"
80 * void A::setup_metrics() {
81 * namespace sm = seastar::metrics;
82 * _metrics = sm::create_metric_group();
83 * _metrics->add_group("cache", {sm::make_gauge("bytes", "used", [this] { return _region.occupancy().used_space(); })});
90 class double_registration : public std::runtime_error {
92 double_registration(std::string what);
96 * \defgroup metrics_types metrics type definitions
97 * The following are for the metric layer use, do not use them directly
98 * Instead use the make_counter, make_gauge, make_absolute and make_derived
101 using metric_type_def = sstring; /*!< Used to hold an inherit type (like bytes)*/
102 using metric_name_type = sstring; /*!< The metric name'*/
103 using instance_id_type = sstring; /*!< typically used for the shard id*/
106 * \brief Human-readable description of a metric/group.
109 * Uses a separate class to deal with type resolution
111 * Add this to metric creation:
114 * _metrics->add_group("groupname", {
115 * sm::make_gauge("metric_name", value, description("A documentation about the return value"))
122 description(sstring s = sstring()) : _s(std::move(s))
124 const sstring& str() const {
132 * \brief Label a metrics
134 * Label are useful for adding information about a metric that
135 * later you would need to aggregate by.
136 * For example, if you have multiple queues on a shard.
137 * Adding the queue id as a Label will allow you to use the same name
138 * of the metrics with multiple id instances.
140 * label_instance holds an instance of label consist of a key and value.
142 * Typically you will not generate a label_instance yourself, but use a label
144 * @see label for more information
148 class label_instance {
153 * \brief create a label_instance
154 * label instance consists of key and value.
155 * The key is an sstring.
156 * T - the value type can be any type that can be lexical_cast to string
157 * (ie. if it support the redirection operator for stringstream).
159 * All primitive types are supported so all the following examples are valid:
160 * label_instance a("smp_queue", 1)
161 * label_instance a("my_key", "my_value")
162 * label_instance a("internal_id", -1)
165 label_instance(const sstring& key, T v) : _key(key), _value(boost::lexical_cast<std::string>(v)){}
168 * \brief returns the label key
170 const sstring key() const {
175 * \brief returns the label value
177 const sstring value() const {
180 bool operator<(const label_instance&) const;
181 bool operator==(const label_instance&) const;
182 bool operator!=(const label_instance&) const;
187 * \brief Class that creates label instances
189 * A factory class to create label instance
190 * Typically, the same Label name is used in multiple places.
191 * label is a label factory, you create it once, and use it to create the label_instance.
193 * In the example we would like to label the smp_queue with with the queue owner
195 * seastar::metrics::label smp_owner("smp_owner");
197 * now, when creating a new smp metric we can add a label to it:
199 * sm::make_queue_length("send_batch_queue_length", _last_snt_batch, {smp_owner(cpuid)})
201 * where cpuid in this case is unsiged.
206 using instance = label_instance;
208 * \brief creating a label
209 * key is the label name, it will be the key for all label_instance
210 * that will be created from this label.
212 explicit label(const sstring& key) : key(key) {
216 * \brief creating a label instance
218 * Use the function operator to create a new label instance.
219 * T - the value type can be any type that can be lexical_cast to string
220 * (ie. if it support the redirection operator for stringstream).
222 * All primitive types are supported so if lab is a label, all the following examples are valid:
228 instance operator()(T value) const {
229 return label_instance(key, std::forward<T>(value));
233 * \brief returns the label name
235 const sstring& name() const {
242 * \brief holds the implementation parts of the metrics layer, do not use directly.
244 * The metrics layer define a thin API for adding metrics.
245 * Some of the implementation details need to be in the header file, they should not be use directly.
249 // The value binding data types
250 enum class data_type : uint8_t {
251 COUNTER, // unsigned int 64
253 DERIVE, // signed int 64
254 ABSOLUTE, // unsigned int 64
259 * \breif A helper class that used to return metrics value.
261 * Do not use directly @see metrics_creation
263 struct metric_value {
264 compat::variant<double, histogram> u;
266 data_type type() const {
271 return compat::get<double>(u);
274 uint64_t ui() const {
275 return compat::get<double>(u);
279 return compat::get<double>(u);
283 : _type(data_type::GAUGE) {
286 metric_value(histogram&& h, data_type t = data_type::HISTOGRAM) :
287 u(std::move(h)), _type(t) {
289 metric_value(const histogram& h, data_type t = data_type::HISTOGRAM) :
293 metric_value(double d, data_type t)
297 metric_value& operator=(const metric_value& c) = default;
299 metric_value& operator+=(const metric_value& c) {
304 metric_value operator+(const metric_value& c);
305 const histogram& get_histogram() const {
306 return compat::get<histogram>(u);
310 using metric_function = std::function<metric_value()>;
314 metric_type_def type_name;
317 struct metric_definition_impl {
318 metric_name_type name;
323 std::map<sstring, sstring> labels;
324 metric_definition_impl& operator ()(bool enabled);
325 metric_definition_impl& operator ()(const label_instance& label);
326 metric_definition_impl(
327 metric_name_type name,
331 std::vector<label_instance> labels);
334 class metric_groups_def {
336 metric_groups_def() = default;
337 virtual ~metric_groups_def() = default;
338 metric_groups_def(const metric_groups_def&) = delete;
339 metric_groups_def(metric_groups_def&&) = default;
340 virtual metric_groups_def& add_metric(group_name_type name, const metric_definition& md) = 0;
341 virtual metric_groups_def& add_group(group_name_type name, const std::initializer_list<metric_definition>& l) = 0;
342 virtual metric_groups_def& add_group(group_name_type name, const std::vector<metric_definition>& l) = 0;
345 instance_id_type shard();
347 template<typename T, typename En = std::true_type>
351 struct is_callable<T, typename std::integral_constant<bool, !std::is_void<typename std::result_of<T()>::type>::value>::type> : public std::true_type {
355 struct is_callable<T, typename std::enable_if<std::is_fundamental<T>::value, std::true_type>::type> : public std::false_type {
358 template<typename T, typename = std::enable_if_t<is_callable<T>::value>>
359 metric_function make_function(T val, data_type dt) {
361 return metric_value(val(), dt);
365 template<typename T, typename = std::enable_if_t<!is_callable<T>::value>>
366 metric_function make_function(T& val, data_type dt) {
368 return metric_value(val, dt);
373 extern const bool metric_disabled;
375 extern label shard_label;
376 extern label type_label;
379 * The metrics definition are defined to be compatible with collectd metrics defintion.
380 * Typically you should used gauge or derived.
385 * \brief Gauge are a general purpose metric.
387 * They can support floating point and can increase or decrease
390 impl::metric_definition_impl make_gauge(metric_name_type name,
391 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
392 return {name, {impl::data_type::GAUGE, "gauge"}, make_function(std::forward<T>(val), impl::data_type::GAUGE), d, labels};
396 * \brief Gauge are a general purpose metric.
398 * They can support floating point and can increase or decrease
401 impl::metric_definition_impl make_gauge(metric_name_type name,
402 description d, T&& val) {
403 return {name, {impl::data_type::GAUGE, "gauge"}, make_function(std::forward<T>(val), impl::data_type::GAUGE), d, {}};
407 * \brief Gauge are a general purpose metric.
409 * They can support floating point and can increase or decrease
412 impl::metric_definition_impl make_gauge(metric_name_type name,
413 description d, std::vector<label_instance> labels, T&& val) {
414 return {name, {impl::data_type::GAUGE, "gauge"}, make_function(std::forward<T>(val), impl::data_type::GAUGE), d, labels};
419 * \brief Derive are used when a rate is more interesting than the value.
421 * Derive is an integer value that can increase or decrease, typically it is used when looking at the
422 * derivation of the value.
424 * It is OK to use it when counting things and if no wrap-around is expected (it shouldn't) it's prefer over counter metric.
427 impl::metric_definition_impl make_derive(metric_name_type name,
428 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
429 return {name, {impl::data_type::DERIVE, "derive"}, make_function(std::forward<T>(val), impl::data_type::DERIVE), d, labels};
434 * \brief Derive are used when a rate is more interesting than the value.
436 * Derive is an integer value that can increase or decrease, typically it is used when looking at the
437 * derivation of the value.
439 * It is OK to use it when counting things and if no wrap-around is expected (it shouldn't) it's prefer over counter metric.
442 impl::metric_definition_impl make_derive(metric_name_type name, description d,
444 return {name, {impl::data_type::DERIVE, "derive"}, make_function(std::forward<T>(val), impl::data_type::DERIVE), d, {}};
449 * \brief Derive are used when a rate is more interesting than the value.
451 * Derive is an integer value that can increase or decrease, typically it is used when looking at the
452 * derivation of the value.
454 * It is OK to use it when counting things and if no wrap-around is expected (it shouldn't) it's prefer over counter metric.
457 impl::metric_definition_impl make_derive(metric_name_type name, description d, std::vector<label_instance> labels,
459 return {name, {impl::data_type::DERIVE, "derive"}, make_function(std::forward<T>(val), impl::data_type::DERIVE), d, labels};
464 * \brief create a counter metric
466 * Counters are similar to derived, but they assume monotony, so if a counter value decrease in a series it is count as a wrap-around.
467 * It is better to use large enough data value than to use counter.
471 impl::metric_definition_impl make_counter(metric_name_type name,
472 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
473 return {name, {impl::data_type::COUNTER, "counter"}, make_function(std::forward<T>(val), impl::data_type::COUNTER), d, labels};
477 * \brief create an absolute metric.
479 * Absolute are used for metric that are being erased after each time they are read.
480 * They are here for compatibility reasons and should general be avoided in most applications.
483 impl::metric_definition_impl make_absolute(metric_name_type name,
484 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
485 return {name, {impl::data_type::ABSOLUTE, "absolute"}, make_function(std::forward<T>(val), impl::data_type::ABSOLUTE), d, labels};
489 * \brief create a histogram metric.
491 * Histograms are a list o buckets with upper values and counter for the number
492 * of entries in each bucket.
495 impl::metric_definition_impl make_histogram(metric_name_type name,
496 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
497 return {name, {impl::data_type::HISTOGRAM, "histogram"}, make_function(std::forward<T>(val), impl::data_type::HISTOGRAM), d, labels};
501 * \brief create a histogram metric.
503 * Histograms are a list o buckets with upper values and counter for the number
504 * of entries in each bucket.
507 impl::metric_definition_impl make_histogram(metric_name_type name,
508 description d, std::vector<label_instance> labels, T&& val) {
509 return {name, {impl::data_type::HISTOGRAM, "histogram"}, make_function(std::forward<T>(val), impl::data_type::HISTOGRAM), d, labels};
514 * \brief create a histogram metric.
516 * Histograms are a list o buckets with upper values and counter for the number
517 * of entries in each bucket.
520 impl::metric_definition_impl make_histogram(metric_name_type name,
521 description d, T&& val) {
522 return {name, {impl::data_type::HISTOGRAM, "histogram"}, make_function(std::forward<T>(val), impl::data_type::HISTOGRAM), d, {}};
527 * \brief create a total_bytes metric.
529 * total_bytes are used for an ever growing counters, like the total bytes
530 * passed on a network.
534 impl::metric_definition_impl make_total_bytes(metric_name_type name,
535 T&& val, description d=description(), std::vector<label_instance> labels = {},
536 instance_id_type instance = impl::shard()) {
537 return make_derive(name, std::forward<T>(val), d, labels)(type_label("total_bytes"));
541 * \brief create a current_bytes metric.
543 * current_bytes are used to report on current status in bytes.
544 * For example the current free memory.
548 impl::metric_definition_impl make_current_bytes(metric_name_type name,
549 T&& val, description d=description(), std::vector<label_instance> labels = {},
550 instance_id_type instance = impl::shard()) {
551 return make_derive(name, std::forward<T>(val), d, labels)(type_label("bytes"));
556 * \brief create a queue_length metric.
558 * queue_length are used to report on queue length
562 impl::metric_definition_impl make_queue_length(metric_name_type name,
563 T&& val, description d=description(), std::vector<label_instance> labels = {},
564 instance_id_type instance = impl::shard()) {
565 return make_gauge(name, std::forward<T>(val), d, labels)(type_label("queue_length"));
570 * \brief create a total operation metric.
572 * total_operations are used for ever growing operation counter.
576 impl::metric_definition_impl make_total_operations(metric_name_type name,
577 T&& val, description d=description(), std::vector<label_instance> labels = {},
578 instance_id_type instance = impl::shard()) {
579 return make_derive(name, std::forward<T>(val), d, labels)(type_label("total_operations"));