]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/include/seastar/core/metrics.hh
update download target update for octopus release
[ceph.git] / ceph / src / seastar / include / seastar / core / metrics.hh
CommitLineData
11fdf7f2
TL
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#include <functional>
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>
29#include <map>
30#include <seastar/core/metrics_types.hh>
31#include <seastar/util/std-compat.hh>
32
33/*! \file metrics.hh
34 * \brief header for metrics creation.
35 *
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.
39 *
40 * Code that is under the impl namespace should not be used directly.
41 *
42 */
43
44namespace seastar {
45
46/*!
47 * \namespace seastar::metrics
48 * \brief metrics creation and registration
49 *
50 * the metrics namespace holds the relevant method and classes to generate metrics.
51 *
52 * The metrics layer support registering metrics, that later will be
53 * exported via different API protocols.
54 *
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
58 *
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.
62 *
63 *
64 * In A header file
65 * \code
66 * #include "core/metrics_registration.hh"
67 * class A {
68 * metric_groups _metrics
69 *
70 * void setup_metrics();
71 *
72 * };
73 * \endcode
74 *
75 * In A source file:
76 *
77 * \code
78 * include "core/metrics.hh"
79 *
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(); })});
84 * }
85 * \endcode
86 */
87
88namespace metrics {
89
90
91/*!
92 * \defgroup metrics_types metrics type definitions
93 * The following are for the metric layer use, do not use them directly
94 * Instead use the make_counter, make_gauge, make_absolute and make_derived
95 *
96 */
97using metric_type_def = sstring; /*!< Used to hold an inherit type (like bytes)*/
98using metric_name_type = sstring; /*!< The metric name'*/
99using instance_id_type = sstring; /*!< typically used for the shard id*/
100
101/*!
102 * \brief Human-readable description of a metric/group.
103 *
104 *
105 * Uses a separate class to deal with type resolution
106 *
107 * Add this to metric creation:
108 *
109 * \code
110 * _metrics->add_group("groupname", {
111 * sm::make_gauge("metric_name", value, description("A documentation about the return value"))
112 * });
113 * \endcode
114 *
115 */
116class description {
117public:
118 description(sstring s = sstring()) : _s(std::move(s))
119 {}
120 const sstring& str() const {
121 return _s;
122 }
123private:
124 sstring _s;
125};
126
127/*!
128 * \brief Label a metrics
129 *
130 * Label are useful for adding information about a metric that
131 * later you would need to aggregate by.
132 * For example, if you have multiple queues on a shard.
133 * Adding the queue id as a Label will allow you to use the same name
134 * of the metrics with multiple id instances.
135 *
136 * label_instance holds an instance of label consist of a key and value.
137 *
138 * Typically you will not generate a label_instance yourself, but use a label
139 * object for that.
140 * @see label for more information
141 *
142 *
143 */
144class label_instance {
145 sstring _key;
146 sstring _value;
147public:
148 /*!
149 * \brief create a label_instance
150 * label instance consists of key and value.
151 * The key is an sstring.
152 * T - the value type can be any type that can be lexical_cast to string
153 * (ie. if it support the redirection operator for stringstream).
154 *
155 * All primitive types are supported so all the following examples are valid:
156 * label_instance a("smp_queue", 1)
157 * label_instance a("my_key", "my_value")
158 * label_instance a("internal_id", -1)
159 */
160 template<typename T>
161 label_instance(const sstring& key, T v) : _key(key), _value(boost::lexical_cast<std::string>(v)){}
162
163 /*!
164 * \brief returns the label key
165 */
166 const sstring key() const {
167 return _key;
168 }
169
170 /*!
171 * \brief returns the label value
172 */
173 const sstring value() const {
174 return _value;
175 }
176 bool operator<(const label_instance&) const;
177 bool operator==(const label_instance&) const;
178 bool operator!=(const label_instance&) const;
179};
180
181
182/*!
183 * \brief Class that creates label instances
184 *
185 * A factory class to create label instance
186 * Typically, the same Label name is used in multiple places.
187 * label is a label factory, you create it once, and use it to create the label_instance.
188 *
189 * In the example we would like to label the smp_queue with with the queue owner
190 *
191 * seastar::metrics::label smp_owner("smp_owner");
192 *
193 * now, when creating a new smp metric we can add a label to it:
194 *
195 * sm::make_queue_length("send_batch_queue_length", _last_snt_batch, {smp_owner(cpuid)})
196 *
197 * where cpuid in this case is unsiged.
198 */
199class label {
200 sstring key;
201public:
202 using instance = label_instance;
203 /*!
204 * \brief creating a label
205 * key is the label name, it will be the key for all label_instance
206 * that will be created from this label.
207 */
208 explicit label(const sstring& key) : key(key) {
209 }
210
211 /*!
212 * \brief creating a label instance
213 *
214 * Use the function operator to create a new label instance.
215 * T - the value type can be any type that can be lexical_cast to string
216 * (ie. if it support the redirection operator for stringstream).
217 *
218 * All primitive types are supported so if lab is a label, all the following examples are valid:
219 * lab(1)
220 * lab("my_value")
221 * lab(-1)
222 */
223 template<typename T>
224 instance operator()(T value) const {
225 return label_instance(key, std::forward<T>(value));
226 }
227
228 /*!
229 * \brief returns the label name
230 */
231 const sstring& name() const {
232 return key;
233 }
234};
235
236/*!
237 * \namesapce impl
238 * \brief holds the implementation parts of the metrics layer, do not use directly.
239 *
240 * The metrics layer define a thin API for adding metrics.
241 * Some of the implementation details need to be in the header file, they should not be use directly.
242 */
243namespace impl {
244
245// The value binding data types
246enum class data_type : uint8_t {
247 COUNTER, // unsigned int 64
248 GAUGE, // double
249 DERIVE, // signed int 64
250 ABSOLUTE, // unsigned int 64
251 HISTOGRAM,
252};
253
254/*!
255 * \breif A helper class that used to return metrics value.
256 *
257 * Do not use directly @see metrics_creation
258 */
259struct metric_value {
260 compat::variant<double, histogram> u;
261 data_type _type;
262 data_type type() const {
263 return _type;
264 }
265
266 double d() const {
267 return compat::get<double>(u);
268 }
269
270 uint64_t ui() const {
271 return compat::get<double>(u);
272 }
273
274 int64_t i() const {
275 return compat::get<double>(u);
276 }
277
278 metric_value()
279 : _type(data_type::GAUGE) {
280 }
281
282 metric_value(histogram&& h, data_type t = data_type::HISTOGRAM) :
283 u(std::move(h)), _type(t) {
284 }
285 metric_value(const histogram& h, data_type t = data_type::HISTOGRAM) :
286 u(h), _type(t) {
287 }
288
289 metric_value(double d, data_type t)
290 : u(d), _type(t) {
291 }
292
293 metric_value& operator=(const metric_value& c) = default;
294
295 metric_value& operator+=(const metric_value& c) {
296 *this = *this + c;
297 return *this;
298 }
299
300 metric_value operator+(const metric_value& c);
301 const histogram& get_histogram() const {
302 return compat::get<histogram>(u);
303 }
304};
305
306using metric_function = std::function<metric_value()>;
307
308struct metric_type {
309 data_type base_type;
310 metric_type_def type_name;
311};
312
313struct metric_definition_impl {
314 metric_name_type name;
315 metric_type type;
316 metric_function f;
317 description d;
318 bool enabled = true;
319 std::map<sstring, sstring> labels;
320 metric_definition_impl& operator ()(bool enabled);
321 metric_definition_impl& operator ()(const label_instance& label);
322 metric_definition_impl(
323 metric_name_type name,
324 metric_type type,
325 metric_function f,
326 description d,
327 std::vector<label_instance> labels);
328};
329
330class metric_groups_def {
331public:
332 metric_groups_def() = default;
333 virtual ~metric_groups_def() = default;
334 metric_groups_def(const metric_groups_def&) = delete;
335 metric_groups_def(metric_groups_def&&) = default;
336 virtual metric_groups_def& add_metric(group_name_type name, const metric_definition& md) = 0;
337 virtual metric_groups_def& add_group(group_name_type name, const std::initializer_list<metric_definition>& l) = 0;
338 virtual metric_groups_def& add_group(group_name_type name, const std::vector<metric_definition>& l) = 0;
339};
340
341instance_id_type shard();
342
343template<typename T, typename En = std::true_type>
344struct is_callable;
345
346template<typename T>
347struct is_callable<T, typename std::integral_constant<bool, !std::is_void<typename std::result_of<T()>::type>::value>::type> : public std::true_type {
348};
349
350template<typename T>
351struct is_callable<T, typename std::enable_if<std::is_fundamental<T>::value, std::true_type>::type> : public std::false_type {
352};
353
354template<typename T, typename = std::enable_if_t<is_callable<T>::value>>
355metric_function make_function(T val, data_type dt) {
356 return [dt, val] {
357 return metric_value(val(), dt);
358 };
359}
360
361template<typename T, typename = std::enable_if_t<!is_callable<T>::value>>
362metric_function make_function(T& val, data_type dt) {
363 return [dt, &val] {
364 return metric_value(val, dt);
365 };
366}
367}
368
369extern const bool metric_disabled;
370
371extern label shard_label;
372extern label type_label;
373
374/*
375 * The metrics definition are defined to be compatible with collectd metrics defintion.
376 * Typically you should used gauge or derived.
377 */
378
379
380/*!
381 * \brief Gauge are a general purpose metric.
382 *
383 * They can support floating point and can increase or decrease
384 */
385template<typename T>
386impl::metric_definition_impl make_gauge(metric_name_type name,
387 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
388 return {name, {impl::data_type::GAUGE, "gauge"}, make_function(std::forward<T>(val), impl::data_type::GAUGE), d, labels};
389}
390
391/*!
392 * \brief Gauge are a general purpose metric.
393 *
394 * They can support floating point and can increase or decrease
395 */
396template<typename T>
397impl::metric_definition_impl make_gauge(metric_name_type name,
398 description d, T&& val) {
399 return {name, {impl::data_type::GAUGE, "gauge"}, make_function(std::forward<T>(val), impl::data_type::GAUGE), d, {}};
400}
401
402/*!
403 * \brief Gauge are a general purpose metric.
404 *
405 * They can support floating point and can increase or decrease
406 */
407template<typename T>
408impl::metric_definition_impl make_gauge(metric_name_type name,
409 description d, std::vector<label_instance> labels, T&& val) {
410 return {name, {impl::data_type::GAUGE, "gauge"}, make_function(std::forward<T>(val), impl::data_type::GAUGE), d, labels};
411}
412
413
414/*!
415 * \brief Derive are used when a rate is more interesting than the value.
416 *
417 * Derive is an integer value that can increase or decrease, typically it is used when looking at the
418 * derivation of the value.
419 *
420 * 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.
421 */
422template<typename T>
423impl::metric_definition_impl make_derive(metric_name_type name,
424 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
425 return {name, {impl::data_type::DERIVE, "derive"}, make_function(std::forward<T>(val), impl::data_type::DERIVE), d, labels};
426}
427
428
429/*!
430 * \brief Derive are used when a rate is more interesting than the value.
431 *
432 * Derive is an integer value that can increase or decrease, typically it is used when looking at the
433 * derivation of the value.
434 *
435 * 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.
436 */
437template<typename T>
438impl::metric_definition_impl make_derive(metric_name_type name, description d,
439 T&& val) {
440 return {name, {impl::data_type::DERIVE, "derive"}, make_function(std::forward<T>(val), impl::data_type::DERIVE), d, {}};
441}
442
443
444/*!
445 * \brief Derive are used when a rate is more interesting than the value.
446 *
447 * Derive is an integer value that can increase or decrease, typically it is used when looking at the
448 * derivation of the value.
449 *
450 * 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.
451 */
452template<typename T>
453impl::metric_definition_impl make_derive(metric_name_type name, description d, std::vector<label_instance> labels,
454 T&& val) {
455 return {name, {impl::data_type::DERIVE, "derive"}, make_function(std::forward<T>(val), impl::data_type::DERIVE), d, labels};
456}
457
458
459/*!
460 * \brief create a counter metric
461 *
462 * 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.
463 * It is better to use large enough data value than to use counter.
464 *
465 */
466template<typename T>
467impl::metric_definition_impl make_counter(metric_name_type name,
468 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
469 return {name, {impl::data_type::COUNTER, "counter"}, make_function(std::forward<T>(val), impl::data_type::COUNTER), d, labels};
470}
471
472/*!
473 * \brief create an absolute metric.
474 *
475 * Absolute are used for metric that are being erased after each time they are read.
476 * They are here for compatibility reasons and should general be avoided in most applications.
477 */
478template<typename T>
479impl::metric_definition_impl make_absolute(metric_name_type name,
480 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
481 return {name, {impl::data_type::ABSOLUTE, "absolute"}, make_function(std::forward<T>(val), impl::data_type::ABSOLUTE), d, labels};
482}
483
484/*!
485 * \brief create a histogram metric.
486 *
487 * Histograms are a list o buckets with upper values and counter for the number
488 * of entries in each bucket.
489 */
490template<typename T>
491impl::metric_definition_impl make_histogram(metric_name_type name,
492 T&& val, description d=description(), std::vector<label_instance> labels = {}) {
493 return {name, {impl::data_type::HISTOGRAM, "histogram"}, make_function(std::forward<T>(val), impl::data_type::HISTOGRAM), d, labels};
494}
495
496/*!
497 * \brief create a histogram metric.
498 *
499 * Histograms are a list o buckets with upper values and counter for the number
500 * of entries in each bucket.
501 */
502template<typename T>
503impl::metric_definition_impl make_histogram(metric_name_type name,
504 description d, std::vector<label_instance> labels, T&& val) {
505 return {name, {impl::data_type::HISTOGRAM, "histogram"}, make_function(std::forward<T>(val), impl::data_type::HISTOGRAM), d, labels};
506}
507
508
509/*!
510 * \brief create a histogram metric.
511 *
512 * Histograms are a list o buckets with upper values and counter for the number
513 * of entries in each bucket.
514 */
515template<typename T>
516impl::metric_definition_impl make_histogram(metric_name_type name,
517 description d, T&& val) {
518 return {name, {impl::data_type::HISTOGRAM, "histogram"}, make_function(std::forward<T>(val), impl::data_type::HISTOGRAM), d, {}};
519}
520
521
522/*!
523 * \brief create a total_bytes metric.
524 *
525 * total_bytes are used for an ever growing counters, like the total bytes
526 * passed on a network.
527 */
528
529template<typename T>
530impl::metric_definition_impl make_total_bytes(metric_name_type name,
531 T&& val, description d=description(), std::vector<label_instance> labels = {},
532 instance_id_type instance = impl::shard()) {
533 return make_derive(name, std::forward<T>(val), d, labels)(type_label("total_bytes"));
534}
535
536/*!
537 * \brief create a current_bytes metric.
538 *
539 * current_bytes are used to report on current status in bytes.
540 * For example the current free memory.
541 */
542
543template<typename T>
544impl::metric_definition_impl make_current_bytes(metric_name_type name,
545 T&& val, description d=description(), std::vector<label_instance> labels = {},
546 instance_id_type instance = impl::shard()) {
547 return make_derive(name, std::forward<T>(val), d, labels)(type_label("bytes"));
548}
549
550
551/*!
552 * \brief create a queue_length metric.
553 *
554 * queue_length are used to report on queue length
555 */
556
557template<typename T>
558impl::metric_definition_impl make_queue_length(metric_name_type name,
559 T&& val, description d=description(), std::vector<label_instance> labels = {},
560 instance_id_type instance = impl::shard()) {
561 return make_gauge(name, std::forward<T>(val), d, labels)(type_label("queue_length"));
562}
563
564
565/*!
566 * \brief create a total operation metric.
567 *
568 * total_operations are used for ever growing operation counter.
569 */
570
571template<typename T>
572impl::metric_definition_impl make_total_operations(metric_name_type name,
573 T&& val, description d=description(), std::vector<label_instance> labels = {},
574 instance_id_type instance = impl::shard()) {
575 return make_derive(name, std::forward<T>(val), d, labels)(type_label("total_operations"));
576}
577
578/*! @} */
579}
580}