]>
Commit | Line | Data |
---|---|---|
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) 2014 Cloudius Systems, Ltd. | |
20 | */ | |
21 | ||
22 | #pragma once | |
23 | ||
24 | #include <type_traits> | |
25 | #include <utility> | |
26 | #include <functional> | |
27 | #include <array> | |
28 | #include <iterator> | |
29 | #include <stdint.h> | |
30 | #include <memory> | |
31 | #include <string> | |
32 | #include <tuple> | |
33 | #include <chrono> | |
34 | #include <boost/program_options.hpp> | |
35 | ||
36 | #include <seastar/core/future.hh> | |
37 | #include <seastar/net/byteorder.hh> | |
38 | #include <seastar/core/shared_ptr.hh> | |
39 | #include <seastar/core/sstring.hh> | |
11fdf7f2 TL |
40 | #include <seastar/util/log.hh> |
41 | ||
42 | #include <seastar/core/metrics_api.hh> | |
43 | ||
44 | namespace seastar { | |
45 | ||
46 | /** | |
47 | * Implementation of rudimentary collectd data gathering. | |
48 | * | |
49 | * Usage is hopefully straight forward. Though, feel free to read | |
50 | * https://collectd.org/wiki/index.php/Naming_schema | |
51 | * for an explanation on the naming model. | |
52 | * | |
53 | * Typically, you'll add values something like: | |
54 | * | |
55 | * scollectd::type_instance_id typ("<pluginname>", "<instance_name>", "<type_name>", "<instance_name>"); | |
56 | * scollectd::add_polled_metric(typ, [<metric var> | scollectd::make_typed(<data_type>, <metric_var>) [, ...]); | |
57 | * | |
58 | * Where | |
f67539c2 TL |
59 | * `<pluginname>` would be the overall 'module', e.g. "cpu" |
60 | * `<instance_name>` -> optional distinguisher between plugin instances. For cpu, the built-in | |
11fdf7f2 TL |
61 | * scollectd::per_cpu_plugin_instance constant is a good choice, i.e. 0->N cpu. |
62 | * If there are no instances (e.g. only one), empty constant is appropriate (none) | |
f67539c2 TL |
63 | * `<type_name>` is the 'type' of metric collected, for ex. "usage" (cpu/0/usage) |
64 | * `<type_instance>` is a distinguisher for metric parts of the type, e.g. "idle", "user", "kernel" | |
11fdf7f2 TL |
65 | * -> cpu/0/usage/idle | cpu/0/usage/user | cpu/0/usage/kernel |
66 | * | |
67 | * Each type instance can bind an arbitrary number of values, ech representing some aspect in turn of the instance. | |
68 | * The structure and interpretation is up to the producer/consumer | |
69 | * | |
70 | * There is a single "scollectd" instance per cpu, and values should be bound locally | |
71 | * to this cpu. Polling is done at a frequency set in the seastar config (def once per s), | |
72 | * and all registered values will be sent via UDP packages to the destination host(s) | |
73 | * | |
74 | * Note that the tuple { plugin, plugin_instance, type, type_instance } is considered a | |
75 | * unique ID for a value registration, so using the same tuple twice will remove the previously | |
76 | * registered values. | |
77 | * | |
78 | * Values can be unregistered at any time, though they must be so on the same thread/cpu | |
79 | * as they we're registered. The "registration" achor type provides RAII style value unregistration | |
80 | * semantics. | |
81 | * | |
82 | */ | |
83 | ||
84 | namespace scollectd { | |
85 | ||
86 | extern seastar::logger logger; | |
87 | ||
88 | using data_type = seastar::metrics::impl::data_type; | |
89 | ||
90 | enum class known_type { | |
91 | // from types.db. Defined collectd types (type_id) selection. | |
92 | // This enum omits the very application specific types, such | |
93 | // as mysql_* etc, since if you really are re-writing mysql | |
94 | // in seastar, you probably know how to look the type up manually... | |
95 | ||
96 | absolute, | |
97 | backends, | |
98 | bitrate, | |
99 | blocked_clients, | |
100 | bytes, | |
101 | cache_eviction, | |
102 | cache_operation, | |
103 | cache_ratio, | |
104 | cache_result, | |
105 | cache_size, | |
106 | capacity, | |
107 | changes_since_last_save, | |
108 | charge, | |
109 | clock_last_meas, | |
110 | clock_last_update, | |
111 | clock_mode, | |
112 | clock_reachability, | |
113 | clock_skew_ppm, | |
114 | clock_state, | |
115 | clock_stratum, | |
116 | compression, | |
117 | compression_ratio, | |
118 | connections, | |
119 | conntrack, | |
120 | contextswitch, | |
121 | count, | |
122 | counter, | |
123 | cpu, | |
124 | cpufreq, | |
125 | current, | |
126 | current_connections, | |
127 | current_sessions, | |
128 | delay, | |
129 | derive, | |
130 | df, | |
131 | df_complex, | |
132 | df_inodes, | |
133 | disk_io_time, | |
134 | disk_latency, | |
135 | disk_merged, | |
136 | disk_octets, | |
137 | disk_ops, | |
138 | disk_ops_complex, | |
139 | disk_time, | |
140 | dns_answer, | |
141 | dns_notify, | |
142 | dns_octets, | |
143 | dns_opcode, | |
144 | dns_qtype, | |
145 | dns_qtype_cached, | |
146 | dns_query, | |
147 | dns_question, | |
148 | dns_rcode, | |
149 | dns_reject, | |
150 | dns_request, | |
151 | dns_resolver, | |
152 | dns_response, | |
153 | dns_transfer, | |
154 | dns_update, | |
155 | dns_zops, | |
156 | drbd_resource, | |
157 | duration, | |
158 | email_check, | |
159 | email_count, | |
160 | email_size, | |
161 | entropy, | |
162 | evicted_keys, | |
163 | expired_keys, | |
164 | fanspeed, | |
165 | file_handles, | |
166 | file_size, | |
167 | files, | |
168 | flow, | |
169 | fork_rate, | |
170 | frequency, | |
171 | frequency_error, | |
172 | frequency_offset, | |
173 | fscache_stat, | |
174 | gauge, | |
175 | hash_collisions, | |
176 | http_request_methods, | |
177 | http_requests, | |
178 | http_response_codes, | |
179 | humidity, | |
180 | if_collisions, | |
181 | if_dropped, | |
182 | if_errors, | |
183 | if_multicast, | |
184 | if_octets, | |
185 | if_packets, | |
186 | if_rx_errors, | |
187 | if_rx_octets, | |
188 | if_tx_errors, | |
189 | if_tx_octets, | |
190 | invocations, | |
191 | io_octets, | |
192 | io_packets, | |
193 | ipt_bytes, | |
194 | ipt_packets, | |
195 | irq, | |
196 | latency, | |
197 | links, | |
198 | load, | |
199 | md_disks, | |
200 | memory, | |
201 | memory_lua, | |
202 | memory_throttle_count, | |
203 | multimeter, | |
204 | mutex_operations, | |
205 | objects, | |
206 | operations, | |
207 | packets, | |
208 | pending_operations, | |
209 | percent, | |
210 | percent_bytes, | |
211 | percent_inodes, | |
212 | ping, | |
213 | ping_droprate, | |
214 | ping_stddev, | |
215 | players, | |
216 | power, | |
217 | pressure, | |
218 | protocol_counter, | |
219 | pubsub, | |
220 | queue_length, | |
221 | records, | |
222 | requests, | |
223 | response_code, | |
224 | response_time, | |
225 | root_delay, | |
226 | root_dispersion, | |
227 | route_etx, | |
228 | route_metric, | |
229 | routes, | |
230 | segments, | |
231 | serial_octets, | |
232 | signal_noise, | |
233 | signal_power, | |
234 | signal_quality, | |
235 | snr, | |
236 | spl, | |
237 | swap, | |
238 | swap_io, | |
239 | tcp_connections, | |
240 | temperature, | |
241 | threads, | |
242 | time_dispersion, | |
243 | time_offset, | |
244 | time_offset_ntp, | |
245 | time_offset_rms, | |
246 | time_ref, | |
247 | timeleft, | |
248 | total_bytes, | |
249 | total_connections, | |
250 | total_objects, | |
251 | total_operations, | |
252 | total_requests, | |
253 | total_sessions, | |
254 | total_threads, | |
255 | total_time_in_ms, | |
256 | total_values, | |
257 | uptime, | |
258 | users, | |
259 | vcl, | |
260 | vcpu, | |
261 | virt_cpu_total, | |
262 | virt_vcpu, | |
263 | vmpage_action, | |
264 | vmpage_faults, | |
265 | vmpage_io, | |
266 | vmpage_number, | |
267 | volatile_changes, | |
268 | voltage, | |
269 | voltage_threshold, | |
270 | vs_memory, | |
271 | vs_processes, | |
272 | vs_threads, | |
273 | }; | |
274 | ||
275 | // don't use directly. use make_typed. | |
276 | template<typename T> | |
277 | struct typed { | |
278 | typed(data_type t, T && v) | |
279 | : type(t), value(std::forward<T>(v)) { | |
280 | } | |
281 | data_type type; | |
282 | T value; | |
283 | }; | |
284 | ||
285 | template<typename T> | |
286 | static inline typed<T> make_typed(data_type type, T&& t) { | |
287 | return typed<T>(type, std::forward<T>(t)); | |
288 | } | |
289 | ||
290 | using plugin_id = seastar::metrics::group_name_type; | |
291 | using plugin_instance_id = seastar::metrics::instance_id_type; | |
292 | using type_id = seastar::metrics::metric_type_def; | |
293 | using type_instance = seastar::metrics::metric_name_type; | |
294 | ||
295 | type_id type_id_for(known_type); | |
296 | ||
297 | using description = seastar::metrics::description; | |
298 | ||
299 | static constexpr unsigned max_collectd_field_text_len = 63; | |
300 | ||
301 | class type_instance_id { | |
302 | static thread_local unsigned _next_truncated_idx; | |
303 | ||
304 | /// truncate a given field to the maximum allowed length | |
9f95a23c | 305 | void truncate(sstring& field, const char* field_desc); |
11fdf7f2 TL |
306 | public: |
307 | type_instance_id() = default; | |
308 | type_instance_id(plugin_id p, plugin_instance_id pi, type_id t, | |
309 | scollectd::type_instance ti = std::string()) | |
310 | : _plugin(std::move(p)), _plugin_instance(std::move(pi)), _type( | |
311 | std::move(t)), _type_instance(std::move(ti)) { | |
312 | // truncate strings to the maximum allowed length | |
313 | truncate(_plugin, "plugin"); | |
314 | truncate(_plugin_instance, "plugin_instance"); | |
315 | truncate(_type, "type"); | |
316 | truncate(_type_instance, "type_instance"); | |
317 | } | |
f67539c2 TL |
318 | type_instance_id(const seastar::metrics::impl::metric_id &id, const type_id& inherit_type) : _plugin(id.group_name()), |
319 | _plugin_instance(id.instance_id()), _type(inherit_type), | |
11fdf7f2 TL |
320 | _type_instance(id.name()) { |
321 | } | |
322 | type_instance_id(type_instance_id &&) = default; | |
323 | type_instance_id(const type_instance_id &) = default; | |
324 | ||
325 | type_instance_id & operator=(type_instance_id &&) = default; | |
326 | type_instance_id & operator=(const type_instance_id &) = default; | |
327 | ||
328 | const plugin_id & plugin() const { | |
329 | return _plugin; | |
330 | } | |
331 | const plugin_instance_id & plugin_instance() const { | |
332 | return _plugin_instance; | |
333 | } | |
334 | const type_id & type() const { | |
335 | return _type; | |
336 | } | |
337 | const scollectd::type_instance & type_instance() const { | |
338 | return _type_instance; | |
339 | } | |
340 | bool operator<(const type_instance_id&) const; | |
341 | bool operator==(const type_instance_id&) const; | |
342 | private: | |
343 | plugin_id _plugin; | |
344 | plugin_instance_id _plugin_instance; | |
345 | type_id _type; | |
346 | scollectd::type_instance _type_instance; | |
347 | }; | |
348 | ||
349 | extern const plugin_instance_id per_cpu_plugin_instance; | |
350 | ||
20effc67 TL |
351 | // Scollectd configuration options. |
352 | struct options : public program_options::option_group { | |
353 | /// \brief Enable collectd daemon. | |
354 | /// | |
355 | /// Default: \p false. | |
356 | program_options::value<bool> collectd; | |
357 | /// \brief Address to send/broadcast metrics to. | |
358 | /// | |
359 | /// Default: \p 239.192.74.66:25826. | |
360 | program_options::value<std::string> collectd_address; | |
361 | /// \brief Poll period (ms). | |
362 | /// | |
363 | /// Frequency of sending counter metrics (0 disables). | |
364 | /// Default: \p 1000. | |
365 | program_options::value<unsigned> collectd_poll_period; | |
366 | /// \deprecated use \ref metrics::options::metrics_hostname instead | |
367 | program_options::value<std::string> collectd_hostname; | |
368 | ||
369 | /// \cond internal | |
370 | options(program_options::option_group* parent_group); | |
371 | /// \endcond | |
372 | }; | |
373 | ||
374 | void configure(const options&); | |
11fdf7f2 TL |
375 | void remove_polled_metric(const type_instance_id &); |
376 | ||
377 | class plugin_instance_metrics; | |
378 | ||
379 | /** | |
380 | * Anchor for polled registration. | |
381 | * Iff the registered type is in some way none-persistent, | |
382 | * use this as receiver of the reg and ensure it dies before the | |
383 | * added value(s). | |
384 | * | |
385 | * Use: | |
386 | * uint64_t v = 0; | |
387 | * registration r = add_polled_metric(v); | |
388 | * ++r; | |
389 | * <scope end, above dies> | |
390 | */ | |
391 | struct registration { | |
392 | registration() = default; | |
393 | registration(const type_instance_id& id); | |
394 | registration(type_instance_id&& id); | |
395 | registration(const registration&) = delete; | |
396 | registration(registration&&) = default; | |
397 | ~registration(); | |
398 | registration & operator=(const registration&) = delete; | |
399 | registration & operator=(registration&&) = default; | |
400 | ||
401 | void unregister() { | |
402 | remove_polled_metric(_id); | |
403 | _id = type_instance_id(); | |
404 | } | |
405 | private: | |
406 | friend class plugin_instance_metrics; | |
407 | type_instance_id _id; | |
408 | shared_ptr<seastar::metrics::impl::impl> _impl; | |
409 | }; | |
410 | ||
411 | /** | |
412 | * Helper type to make generating vectors of registration objects | |
413 | * easier, since it constructs from an initializer list of | |
414 | * type_instance_id:s, avoiding early conversion to registration objs, | |
415 | * which in case of init lists, are copy semantics, not move... | |
416 | */ | |
417 | class registrations | |
418 | : public std::vector<registration> | |
419 | { | |
420 | public: | |
421 | typedef std::vector<registration> vector_type; | |
422 | ||
423 | registrations() | |
424 | {} | |
425 | registrations(vector_type&& v) : vector_type(std::move(v)) | |
426 | {} | |
427 | registrations(const std::initializer_list<type_instance_id>& l) | |
428 | : vector_type(l.begin(),l.end()) | |
429 | {} | |
430 | registrations& operator=(vector_type&& v) { | |
431 | vector_type::operator=(std::move(v)); | |
432 | return *this; | |
433 | } | |
434 | registrations& operator=(const std::initializer_list<type_instance_id>& l) { | |
435 | return registrations::operator=(registrations(l)); | |
436 | } | |
437 | }; | |
438 | ||
439 | class value_list; | |
440 | ||
441 | struct typed_value { | |
442 | /** | |
443 | * Wraps N values of a given type (type_id). | |
444 | * Used to group types into a plugin_instance_metrics | |
445 | */ | |
446 | template<typename... Args> | |
447 | typed_value(const type_id& tid, const scollectd::type_instance& ti, description, Args&&... args); | |
448 | ||
449 | template<typename... Args> | |
450 | typed_value(const type_id& tid, const scollectd::type_instance& ti, Args&&... args) | |
451 | : typed_value(tid, ti, description(), std::forward<Args>(args)...) | |
452 | {} | |
453 | ||
454 | const scollectd::type_instance& type_instance() const { | |
455 | return _type_instance; | |
456 | } | |
457 | const shared_ptr<value_list>& values() const { | |
458 | return _values; | |
459 | } | |
460 | const type_id & type() const { | |
461 | return _type_id; | |
462 | } | |
463 | private: | |
464 | type_id _type_id; | |
465 | scollectd::type_instance _type_instance; | |
466 | shared_ptr<value_list> _values; | |
467 | }; | |
468 | ||
469 | class plugin_instance_metrics { | |
470 | public: | |
471 | template<typename... TypedValues> | |
472 | plugin_instance_metrics(const plugin_id& p, const plugin_instance_id& pi, TypedValues&&... values) | |
473 | : _plugin_id(p) | |
474 | , _plugin_instance(pi) | |
475 | , _registrations({ add_impl(values)... }) | |
476 | {} | |
477 | std::vector<type_instance_id> bound_ids() const; | |
478 | void add(const typed_value&); | |
479 | private: | |
480 | type_instance_id add_impl(const typed_value&); | |
481 | ||
482 | plugin_id _plugin_id; | |
483 | plugin_instance_id _plugin_instance; | |
484 | registrations _registrations; | |
485 | }; | |
486 | ||
487 | /** | |
488 | * Simplified wrapper for the common case of per-cpu plugin instances | |
489 | * (i.e. distributed objects) | |
490 | */ | |
491 | class percpu_plugin_instance_metrics : public plugin_instance_metrics { | |
492 | public: | |
493 | template<typename... TypedValues> | |
494 | percpu_plugin_instance_metrics(const plugin_id& p, TypedValues&&... values) | |
495 | : plugin_instance_metrics(p, per_cpu_plugin_instance, std::forward<TypedValues>(values)...) | |
496 | {} | |
497 | }; | |
498 | ||
499 | /** | |
500 | * Template wrapper for type_id values, deriving type_id string | |
501 | * from the known_types enum, for auto-completetion joy. | |
502 | */ | |
503 | template<known_type Type> | |
504 | struct typed_value_impl: public typed_value { | |
505 | template<typename ... Args> | |
506 | typed_value_impl(const scollectd::type_instance& ti, Args&& ... args) | |
507 | : typed_value(type_id_for(Type), ti, std::forward<Args>(args)...) | |
508 | {} | |
509 | ||
510 | template<typename ... Args> | |
511 | typed_value_impl(scollectd::type_instance ti, description d, Args&& ... args) | |
512 | : typed_value(type_id_for(Type), std::move(ti), std::move(d), std::forward<Args>(args)...) | |
513 | {} | |
514 | template<typename ... Args> | |
515 | typed_value_impl(description d, Args&& ... args) | |
516 | : typed_value(type_id_for(Type), scollectd::type_instance(), std::move(d), std::forward<Args>(args)...) | |
517 | {} | |
518 | }; | |
519 | ||
520 | /*! | |
521 | * \deprecated metrics registration should be done using the metrics layer | |
522 | * | |
523 | * Some typedefs for common used types. Feel free to add. | |
524 | */ | |
525 | typedef typed_value_impl<known_type::total_bytes> total_bytes; | |
526 | typedef typed_value_impl<known_type::total_connections> total_connections; | |
527 | typedef typed_value_impl<known_type::total_objects> total_objects; | |
528 | typedef typed_value_impl<known_type::total_operations> total_operations; | |
529 | typedef typed_value_impl<known_type::total_requests> total_requests; | |
530 | typedef typed_value_impl<known_type::total_sessions> total_sessions; | |
531 | typedef typed_value_impl<known_type::total_threads> total_threads; | |
532 | typedef typed_value_impl<known_type::total_time_in_ms> total_time_in_ms; | |
533 | typedef typed_value_impl<known_type::total_values> total_values; | |
534 | typedef typed_value_impl<known_type::queue_length> queue_length; | |
535 | typedef typed_value_impl<known_type::counter> counter; | |
536 | typedef typed_value_impl<known_type::count> count; | |
537 | typedef typed_value_impl<known_type::gauge> gauge; | |
538 | ||
539 | // lots of template junk to build typed value list tuples | |
540 | // for registered values. | |
541 | template<typename T, typename En = void> | |
542 | struct data_type_for; | |
543 | ||
544 | template<typename T, typename En = void> | |
545 | struct is_callable; | |
546 | ||
547 | template<typename T> | |
548 | struct is_callable<T, | |
549 | typename std::enable_if< | |
20effc67 | 550 | !std::is_void<std::invoke_result_t<T>>::value, |
11fdf7f2 TL |
551 | void>::type> : public std::true_type { |
552 | }; | |
553 | ||
554 | template<typename T> | |
555 | struct is_callable<T, | |
556 | typename std::enable_if<std::is_fundamental<T>::value, void>::type> : public std::false_type { | |
557 | }; | |
558 | ||
559 | template<typename T> | |
560 | struct data_type_for<T, | |
561 | typename std::enable_if< | |
562 | std::is_integral<T>::value && std::is_unsigned<T>::value, | |
563 | void>::type> : public std::integral_constant<data_type, | |
564 | data_type::COUNTER> { | |
565 | }; | |
566 | template<typename T> | |
567 | struct data_type_for<T, | |
568 | typename std::enable_if< | |
569 | std::is_integral<T>::value && std::is_signed<T>::value, void>::type> : public std::integral_constant< | |
570 | data_type, data_type::DERIVE> { | |
571 | }; | |
572 | template<typename T> | |
573 | struct data_type_for<T, | |
574 | typename std::enable_if<std::is_floating_point<T>::value, void>::type> : public std::integral_constant< | |
575 | data_type, data_type::GAUGE> { | |
576 | }; | |
577 | template<typename T> | |
578 | struct data_type_for<T, | |
579 | typename std::enable_if<is_callable<T>::value, void>::type> : public data_type_for< | |
20effc67 | 580 | std::invoke_result_t<T>> { |
11fdf7f2 TL |
581 | }; |
582 | template<typename T> | |
583 | struct data_type_for<typed<T>> : public data_type_for<T> { | |
584 | }; | |
585 | ||
586 | template<typename T> | |
587 | class value { | |
588 | public: | |
589 | template<typename W> | |
590 | struct wrap { | |
591 | wrap(const W & v) | |
592 | : _v(v) { | |
593 | } | |
594 | const W & operator()() const { | |
595 | return _v; | |
596 | } | |
597 | const W & _v; | |
598 | }; | |
599 | ||
600 | typedef typename std::remove_reference<T>::type value_type; | |
601 | typedef typename std::conditional< | |
602 | is_callable<typename std::remove_reference<T>::type>::value, | |
603 | value_type, wrap<value_type> >::type stored_type; | |
604 | ||
605 | value(const value_type & t) | |
606 | : value<T>(data_type_for<value_type>::value, t) { | |
607 | } | |
608 | value(data_type type, const value_type & t) | |
609 | : _type(type), _t(t) { | |
610 | } | |
611 | uint64_t operator()() const { | |
612 | auto v = _t(); | |
613 | if (_type == data_type::GAUGE) { | |
614 | return convert(double(v)); | |
615 | } else { | |
616 | uint64_t u = v; | |
617 | return convert(u); | |
618 | } | |
619 | } | |
620 | operator uint64_t() const { | |
621 | return (*this)(); | |
622 | } | |
623 | operator data_type() const { | |
624 | return _type; | |
625 | } | |
626 | data_type type() const { | |
627 | return _type; | |
628 | } | |
629 | private: | |
630 | // not super quick value -> protocol endian 64-bit values. | |
631 | template<typename _Iter> | |
632 | void bpack(_Iter s, _Iter e, uint64_t v) const { | |
633 | while (s != e) { | |
634 | *s++ = (v & 0xff); | |
635 | v >>= 8; | |
636 | } | |
637 | } | |
638 | template<typename V> | |
639 | typename std::enable_if<std::is_integral<V>::value, uint64_t>::type convert( | |
640 | V v) const { | |
641 | uint64_t i = v; | |
642 | // network byte order | |
643 | return ntohq(i); | |
644 | } | |
645 | template<typename V> | |
646 | typename std::enable_if<std::is_floating_point<V>::value, uint64_t>::type convert( | |
647 | V t) const { | |
648 | union { | |
649 | uint64_t i; | |
650 | double v; | |
651 | } v; | |
652 | union { | |
653 | uint64_t i; | |
654 | uint8_t b[8]; | |
655 | } u; | |
656 | v.v = t; | |
657 | // intel byte order. could also obviously be faster. | |
658 | // could be ignored if we just assume we're le (for now), | |
659 | // but this is ok me thinks. | |
660 | bpack(std::begin(u.b), std::end(u.b), v.i); | |
661 | return u.i; | |
662 | } | |
663 | ; | |
664 | ||
665 | const data_type _type; | |
666 | const stored_type _t; | |
667 | }; | |
668 | ||
669 | template<typename T> | |
670 | class value<typed<T>> : public value<T> { | |
671 | public: | |
672 | value(const typed<T> & args) | |
673 | : value<T>(args.type, args.value) { | |
674 | } | |
675 | }; | |
676 | ||
677 | class value_list { | |
678 | bool _enabled = true; | |
679 | public: | |
680 | value_list(description d) : _description(std::move(d)) | |
681 | {} | |
682 | value_list(value_list&&) = default; | |
683 | virtual ~value_list() {} | |
684 | ||
685 | virtual size_t size() const = 0; | |
686 | ||
687 | virtual void types(data_type *) const = 0; | |
688 | virtual void values(net::packed<uint64_t> *) const = 0; | |
689 | ||
690 | const description& desc() const { | |
691 | return _description; | |
692 | } | |
693 | ||
694 | bool empty() const { | |
695 | return size() == 0; | |
696 | } | |
697 | ||
698 | bool is_enabled() const { | |
699 | return _enabled; | |
700 | } | |
701 | ||
702 | void set_enabled(bool b) { | |
703 | _enabled = b; | |
704 | } | |
705 | private: | |
706 | description _description; | |
707 | }; | |
708 | ||
709 | template<typename ... Args> | |
710 | class values_impl: public value_list { | |
711 | public: | |
712 | static const size_t num_values = sizeof...(Args); | |
713 | ||
714 | values_impl(description d, Args&& ...args) | |
715 | : value_list(std::move(d)) | |
716 | , _values(std::forward<Args>(args)...) | |
717 | {} | |
718 | ||
719 | values_impl(values_impl<Args...>&& a) = default; | |
720 | values_impl(const values_impl<Args...>& a) = default; | |
721 | ||
722 | size_t size() const override { | |
723 | return num_values; | |
724 | } | |
725 | void types(data_type * p) const override { | |
726 | unpack(_values, [p](Args... args) { | |
727 | std::initializer_list<data_type> tmp = { args... }; | |
728 | std::copy(tmp.begin(), tmp.end(), p); | |
729 | }); | |
730 | } | |
731 | void values(net::packed<uint64_t> * p) const override { | |
732 | unpack(_values, [p](Args... args) { | |
733 | std::initializer_list<uint64_t> tmp = { args... }; | |
734 | std::copy(tmp.begin(), tmp.end(), p); | |
735 | }); | |
736 | } | |
737 | private: | |
738 | template<typename _Op> | |
739 | void unpack(const std::tuple<Args...>& t, _Op&& op) const { | |
740 | do_unpack(t, std::index_sequence_for<Args...> {}, std::forward<_Op>(op)); | |
741 | } | |
742 | ||
743 | template<size_t ...S, typename _Op> | |
744 | void do_unpack(const std::tuple<Args...>& t, const std::index_sequence<S...> &, _Op&& op) const { | |
745 | op(std::get<S>(t)...); | |
746 | } | |
747 | ||
748 | std::tuple < Args... > _values; | |
749 | }; | |
750 | ||
751 | void add_polled(const type_instance_id &, const shared_ptr<value_list> &, bool enabled = true); | |
752 | ||
753 | typedef std::function<void()> notify_function; | |
754 | template<typename... _Args> | |
755 | static auto make_type_instance(description d, _Args && ... args) -> values_impl < decltype(value<_Args>(std::forward<_Args>(args)))... > | |
756 | { | |
757 | return values_impl<decltype(value<_Args>(std::forward<_Args>(args)))...>( | |
758 | std::move(d), value<_Args>(std::forward<_Args>(args))...); | |
759 | } | |
760 | /*! | |
761 | * \deprecated metrics registration should be done using the metrics layer | |
762 | * | |
763 | */ | |
764 | template<typename ... _Args> | |
765 | [[deprecated("Use the metrics layer")]] static type_instance_id add_polled_metric(const plugin_id & plugin, | |
766 | const plugin_instance_id & plugin_instance, const type_id & type, | |
767 | const scollectd::type_instance & type_instance, _Args&& ... args) { | |
768 | return add_polled_metric(plugin, plugin_instance, type, type_instance, description(), | |
769 | std::forward<_Args>(args)...); | |
770 | } | |
771 | /*! | |
772 | * \deprecated metrics registration should be done using the metrics layer | |
773 | * | |
774 | */ | |
775 | template<typename ... _Args> | |
776 | [[deprecated("Use the metrics layer")]] static type_instance_id add_polled_metric(const plugin_id & plugin, | |
777 | const plugin_instance_id & plugin_instance, const type_id & type, | |
778 | const scollectd::type_instance & type_instance, description d, _Args&& ... args) { | |
779 | return add_polled_metric( | |
780 | type_instance_id(plugin, plugin_instance, type, type_instance), std::move(d), | |
781 | std::forward<_Args>(args)...); | |
782 | } | |
783 | template<typename ... _Args> | |
784 | static future<> send_explicit_metric(const plugin_id & plugin, | |
785 | const plugin_instance_id & plugin_instance, const type_id & type, | |
786 | const scollectd::type_instance & type_instance, _Args&& ... args) { | |
787 | return send_explicit_metric( | |
788 | type_instance_id(plugin, plugin_instance, type, type_instance), | |
789 | std::forward<_Args>(args)...); | |
790 | } | |
791 | template<typename ... _Args> | |
792 | static notify_function create_explicit_metric(const plugin_id & plugin, | |
793 | const plugin_instance_id & plugin_instance, const type_id & type, | |
794 | const scollectd::type_instance & type_instance, _Args&& ... args) { | |
795 | return create_explicit_metric( | |
796 | type_instance_id(plugin, plugin_instance, type, type_instance), | |
797 | std::forward<_Args>(args)...); | |
798 | } | |
799 | ||
800 | seastar::metrics::impl::metric_id to_metrics_id(const type_instance_id & id); | |
801 | /*! | |
802 | * \deprecated metrics registration should be done using the metrics layer | |
803 | * | |
804 | */ | |
805 | template<typename Arg> | |
806 | [[deprecated("Use the metrics layer")]] static type_instance_id add_polled_metric(const type_instance_id & id, description d, | |
807 | Arg&& arg, bool enabled = true) { | |
f67539c2 | 808 | seastar::metrics::impl::get_local_impl()->add_registration(to_metrics_id(id), arg.type, seastar::metrics::impl::make_function(arg.value, arg.type), d, enabled); |
11fdf7f2 TL |
809 | return id; |
810 | } | |
811 | /*! | |
812 | * \deprecated metrics registration should be done using the metrics layer | |
813 | * | |
814 | */ | |
815 | template<typename Arg> | |
816 | [[deprecated("Use the metrics layer")]] static type_instance_id add_polled_metric(const type_instance_id & id, | |
817 | Arg&& arg) { | |
818 | return std::move(add_polled_metric(id, description(), std::forward<Arg>(arg))); | |
819 | } | |
820 | ||
821 | /*! | |
822 | * \deprecated metrics registration should be done using the metrics layer | |
823 | * | |
824 | */ | |
825 | template<typename Args> | |
826 | [[deprecated("Use the metrics layer")]] static type_instance_id add_disabled_polled_metric(const type_instance_id & id, description d, | |
827 | Args&& arg) { | |
828 | return add_polled_metric(id, d, std::forward<Args>(arg), false); | |
829 | } | |
830 | ||
831 | template<typename Args> | |
832 | static type_instance_id add_disabled_polled_metric(const type_instance_id & id, | |
833 | Args&& args) { | |
834 | return add_disabled_polled_metric(id, description(), std::forward<Args>(args)); | |
835 | } | |
836 | ||
837 | template<typename ... Args> | |
838 | static type_instance_id add_disabled_polled_metric(const type_instance_id & id, | |
839 | Args&& ... args) { | |
840 | return add_disabled_polled_metric(id, description(), std::forward<Args>(args)...); | |
841 | } | |
842 | ||
843 | // "Explicit" metric sends. Sends a single value list as a message. | |
844 | // Obviously not super efficient either. But maybe someone needs it sometime. | |
845 | template<typename ... _Args> | |
846 | static future<> send_explicit_metric(const type_instance_id & id, | |
847 | _Args&& ... args) { | |
848 | return send_metric(id, make_type_instance(std::forward<_Args>(args)...)); | |
849 | } | |
850 | template<typename ... _Args> | |
851 | static notify_function create_explicit_metric(const type_instance_id & id, | |
852 | _Args&& ... args) { | |
853 | auto list = make_type_instance(std::forward<_Args>(args)...); | |
854 | return [id, list=std::move(list)]() { | |
855 | send_metric(id, list); | |
856 | }; | |
857 | } | |
858 | ||
859 | template<typename... Args> | |
860 | typed_value::typed_value(const type_id& tid, const scollectd::type_instance& ti, description d, Args&&... args) | |
861 | : _type_id(tid) | |
862 | , _type_instance(ti) | |
863 | , _values(::seastar::make_shared<decltype(make_type_instance(std::move(d), std::forward<Args>(args)...))>(make_type_instance(std::move(d), std::forward<Args>(args)...))) | |
864 | {} | |
865 | ||
866 | // Send a message packet (string) | |
867 | future<> send_notification(const type_instance_id & id, const sstring & msg); | |
868 | }; | |
869 | ||
870 | } |