Seastar
High performance C++ framework for concurrent servers
scollectd.hh
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#ifndef SEASTAR_MODULE
25#include <type_traits>
26#include <utility>
27#include <functional>
28#include <array>
29#include <iterator>
30#include <stdint.h>
31#include <memory>
32#include <string>
33#include <tuple>
34#include <chrono>
35#endif
36
37#include <seastar/core/future.hh>
38#include <seastar/net/byteorder.hh>
39#include <seastar/core/shared_ptr.hh>
40#include <seastar/core/sstring.hh>
41#include <seastar/util/log.hh>
42#include <seastar/util/program-options.hh>
43#include <seastar/util/modules.hh>
45
46namespace seastar {
47
86namespace scollectd {
87
88extern seastar::logger logger;
89
90using data_type = seastar::metrics::impl::data_type;
91
92enum class known_type {
93 // from types.db. Defined collectd types (type_id) selection.
94 // This enum omits the very application specific types, such
95 // as mysql_* etc, since if you really are re-writing mysql
96 // in seastar, you probably know how to look the type up manually...
97
98 absolute,
99 backends,
100 bitrate,
101 blocked_clients,
102 bytes,
103 cache_eviction,
104 cache_operation,
105 cache_ratio,
106 cache_result,
107 cache_size,
108 capacity,
109 changes_since_last_save,
110 charge,
111 clock_last_meas,
112 clock_last_update,
113 clock_mode,
114 clock_reachability,
115 clock_skew_ppm,
116 clock_state,
117 clock_stratum,
118 compression,
119 compression_ratio,
120 connections,
121 conntrack,
122 contextswitch,
123 count,
124 counter,
125 cpu,
126 cpufreq,
127 current,
128 current_connections,
129 current_sessions,
130 delay,
131 derive,
132 df,
133 df_complex,
134 df_inodes,
135 disk_io_time,
136 disk_latency,
137 disk_merged,
138 disk_octets,
139 disk_ops,
140 disk_ops_complex,
141 disk_time,
142 dns_answer,
143 dns_notify,
144 dns_octets,
145 dns_opcode,
146 dns_qtype,
147 dns_qtype_cached,
148 dns_query,
149 dns_question,
150 dns_rcode,
151 dns_reject,
152 dns_request,
153 dns_resolver,
154 dns_response,
155 dns_transfer,
156 dns_update,
157 dns_zops,
158 drbd_resource,
159 duration,
160 email_check,
161 email_count,
162 email_size,
163 entropy,
164 evicted_keys,
165 expired_keys,
166 fanspeed,
167 file_handles,
168 file_size,
169 files,
170 flow,
171 fork_rate,
172 frequency,
173 frequency_error,
174 frequency_offset,
175 fscache_stat,
176 gauge,
177 hash_collisions,
178 http_request_methods,
179 http_requests,
180 http_response_codes,
181 humidity,
182 if_collisions,
183 if_dropped,
184 if_errors,
185 if_multicast,
186 if_octets,
187 if_packets,
188 if_rx_errors,
189 if_rx_octets,
190 if_tx_errors,
191 if_tx_octets,
192 invocations,
193 io_octets,
194 io_packets,
195 ipt_bytes,
196 ipt_packets,
197 irq,
198 latency,
199 links,
200 load,
201 md_disks,
202 memory,
203 memory_lua,
204 memory_throttle_count,
205 multimeter,
206 mutex_operations,
207 objects,
208 operations,
209 packets,
210 pending_operations,
211 percent,
212 percent_bytes,
213 percent_inodes,
214 ping,
215 ping_droprate,
216 ping_stddev,
217 players,
218 power,
219 pressure,
220 protocol_counter,
221 pubsub,
223 records,
224 requests,
225 response_code,
226 response_time,
227 root_delay,
228 root_dispersion,
229 route_etx,
230 route_metric,
231 routes,
232 segments,
233 serial_octets,
234 signal_noise,
235 signal_power,
236 signal_quality,
237 snr,
238 spl,
239 swap,
240 swap_io,
241 tcp_connections,
242 temperature,
243 threads,
244 time_dispersion,
245 time_offset,
246 time_offset_ntp,
247 time_offset_rms,
248 time_ref,
249 timeleft,
259 uptime,
260 users,
261 vcl,
262 vcpu,
263 virt_cpu_total,
264 virt_vcpu,
265 vmpage_action,
266 vmpage_faults,
267 vmpage_io,
268 vmpage_number,
269 volatile_changes,
270 voltage,
271 voltage_threshold,
272 vs_memory,
273 vs_processes,
274 vs_threads,
275};
276
277// don't use directly. use make_typed.
278template<typename T>
279struct typed {
280 typed(data_type t, T && v)
281 : type(t), value(std::forward<T>(v)) {
282 }
283 data_type type;
284 T value;
285};
286
287template<typename T>
288inline typed<T> make_typed(data_type type, T&& t) {
289 return typed<T>(type, std::forward<T>(t));
290}
291
292using plugin_id = seastar::metrics::group_name_type;
293using plugin_instance_id = seastar::metrics::instance_id_type;
295using type_instance = seastar::metrics::metric_name_type;
296
297type_id type_id_for(known_type);
298
299using description = seastar::metrics::description;
300
301static constexpr unsigned max_collectd_field_text_len = 63;
302
304 static thread_local unsigned _next_truncated_idx;
305
307 void truncate(sstring& field, const char* field_desc);
308public:
309 type_instance_id() = default;
310 type_instance_id(plugin_id p, plugin_instance_id pi, type_id t,
311 scollectd::type_instance ti = std::string())
312 : _plugin(std::move(p)), _plugin_instance(std::move(pi)), _type(
313 std::move(t)), _type_instance(std::move(ti)) {
314 // truncate strings to the maximum allowed length
315 truncate(_plugin, "plugin");
316 truncate(_plugin_instance, "plugin_instance");
317 truncate(_type, "type");
318 truncate(_type_instance, "type_instance");
319 }
320 type_instance_id(const seastar::metrics::impl::metric_id &id, const type_id& inherit_type) : _plugin(id.group_name()),
321 _plugin_instance(id.instance_id()), _type(inherit_type),
322 _type_instance(id.name()) {
323 }
325 type_instance_id(const type_instance_id &) = default;
326
327 type_instance_id & operator=(type_instance_id &&) = default;
328 type_instance_id & operator=(const type_instance_id &) = default;
329
330 const plugin_id & plugin() const {
331 return _plugin;
332 }
333 const plugin_instance_id & plugin_instance() const {
334 return _plugin_instance;
335 }
336 const type_id & type() const {
337 return _type;
338 }
339 const scollectd::type_instance & type_instance() const {
340 return _type_instance;
341 }
342 bool operator<(const type_instance_id&) const;
343 bool operator==(const type_instance_id&) const;
344private:
345 plugin_id _plugin;
346 plugin_instance_id _plugin_instance;
347 type_id _type;
348 scollectd::type_instance _type_instance;
349};
350
351extern const plugin_instance_id per_cpu_plugin_instance;
352
353// Scollectd configuration options.
370
374};
375
376void configure(const options&);
377void remove_polled_metric(const type_instance_id &);
378
380
394 registration() = default;
397 registration(const registration&) = delete;
398 registration(registration&&) = default;
400 registration & operator=(const registration&) = delete;
401 registration & operator=(registration&&) = default;
402
403 void unregister() {
404 remove_polled_metric(_id);
405 _id = type_instance_id();
406 }
407private:
408 friend class plugin_instance_metrics;
411};
412
420 : public std::vector<registration>
421{
422public:
423 typedef std::vector<registration> vector_type;
424
426 {}
427 registrations(vector_type&& v) : vector_type(std::move(v))
428 {}
429 registrations(const std::initializer_list<type_instance_id>& l)
430 : vector_type(l.begin(),l.end())
431 {}
432 registrations& operator=(vector_type&& v) {
433 vector_type::operator=(std::move(v));
434 return *this;
435 }
436 registrations& operator=(const std::initializer_list<type_instance_id>& l) {
437 return registrations::operator=(registrations(l));
438 }
439};
440
441class value_list;
442
448 template<typename... Args>
449 typed_value(const type_id& tid, const scollectd::type_instance& ti, description, Args&&... args);
450
451 template<typename... Args>
452 typed_value(const type_id& tid, const scollectd::type_instance& ti, Args&&... args)
453 : typed_value(tid, ti, description(), std::forward<Args>(args)...)
454 {}
455
456 const scollectd::type_instance& type_instance() const {
457 return _type_instance;
458 }
459 const shared_ptr<value_list>& values() const {
460 return _values;
461 }
462 const type_id & type() const {
463 return _type_id;
464 }
465private:
466 type_id _type_id;
467 scollectd::type_instance _type_instance;
469};
470
472public:
473 template<typename... TypedValues>
474 plugin_instance_metrics(const plugin_id& p, const plugin_instance_id& pi, TypedValues&&... values)
475 : _plugin_id(p)
476 , _plugin_instance(pi)
477 , _registrations({ add_impl(values)... })
478 {}
479 std::vector<type_instance_id> bound_ids() const;
480 void add(const typed_value&);
481private:
482 type_instance_id add_impl(const typed_value&);
483
484 plugin_id _plugin_id;
485 plugin_instance_id _plugin_instance;
486 registrations _registrations;
487};
488
494public:
495 template<typename... TypedValues>
496 percpu_plugin_instance_metrics(const plugin_id& p, TypedValues&&... values)
497 : plugin_instance_metrics(p, per_cpu_plugin_instance, std::forward<TypedValues>(values)...)
498 {}
499};
500
505template<known_type Type>
507 template<typename ... Args>
508 typed_value_impl(const scollectd::type_instance& ti, Args&& ... args)
509 : typed_value(type_id_for(Type), ti, std::forward<Args>(args)...)
510 {}
511
512 template<typename ... Args>
513 typed_value_impl(scollectd::type_instance ti, description d, Args&& ... args)
514 : typed_value(type_id_for(Type), std::move(ti), std::move(d), std::forward<Args>(args)...)
515 {}
516 template<typename ... Args>
517 typed_value_impl(description d, Args&& ... args)
518 : typed_value(type_id_for(Type), scollectd::type_instance(), std::move(d), std::forward<Args>(args)...)
519 {}
520};
521
540
541// lots of template junk to build typed value list tuples
542// for registered values.
543template<typename T, typename En = void>
545
546template<typename T, typename En = void>
548
549template<typename T>
550struct is_callable<T,
551std::enable_if_t<
552!std::is_void_v<std::invoke_result_t<T>>,
553void>> : public std::true_type {
554};
555
556template<typename T>
557struct is_callable<T,
558std::enable_if_t<std::is_fundamental_v<T>, void>> : public std::false_type {
559};
560
561template<typename T>
563std::enable_if_t<
564std::is_integral_v<T> && std::is_unsigned_v<T>,
565void>> : public std::integral_constant<data_type,
566data_type::COUNTER> {
567};
568template<typename T>
570std::enable_if_t<std::is_floating_point_v<T>, void>> : public std::integral_constant<
571data_type, data_type::GAUGE> {
572};
573template<typename T>
575std::enable_if_t<is_callable<T>::value, void>> : public data_type_for<
576std::invoke_result_t<T>> {
577};
578template<typename T>
579struct data_type_for<typed<T>> : public data_type_for<T> {
580};
581
582template<typename T>
583class value {
584public:
585 template<typename W>
586 struct wrap {
587 wrap(const W & v)
588 : _v(v) {
589 }
590 const W & operator()() const {
591 return _v;
592 }
593 const W & _v;
594 };
595
596 typedef std::remove_reference_t<T> value_type;
597 typedef std::conditional_t<
599 value_type, wrap<value_type> > stored_type;
600
601 value(const value_type & t)
602 : value<T>(data_type_for<value_type>::value, t) {
603 }
604 value(data_type type, const value_type & t)
605 : _type(type), _t(t) {
606 }
607 uint64_t operator()() const {
608 auto v = _t();
609 if (_type == data_type::GAUGE) {
610 return convert(double(v));
611 } else {
612 uint64_t u = v;
613 return convert(u);
614 }
615 }
616 operator uint64_t() const {
617 return (*this)();
618 }
619 operator data_type() const {
620 return _type;
621 }
622 data_type type() const {
623 return _type;
624 }
625private:
626 // not super quick value -> protocol endian 64-bit values.
627 template<typename _Iter>
628 void bpack(_Iter s, _Iter e, uint64_t v) const {
629 while (s != e) {
630 *s++ = (v & 0xff);
631 v >>= 8;
632 }
633 }
634 template<typename V>
635 std::enable_if_t<std::is_integral_v<V>, uint64_t> convert(
636 V v) const {
637 uint64_t i = v;
638 // network byte order
639 return ntohq(i);
640 }
641 template<typename V>
642 std::enable_if_t<std::is_floating_point_v<V>, uint64_t> convert(
643 V t) const {
644 union {
645 uint64_t i;
646 double v;
647 } v;
648 union {
649 uint64_t i;
650 uint8_t b[8];
651 } u;
652 v.v = t;
653 // intel byte order. could also obviously be faster.
654 // could be ignored if we just assume we're le (for now),
655 // but this is ok me thinks.
656 bpack(std::begin(u.b), std::end(u.b), v.i);
657 return u.i;
658 }
659 ;
660
661 const data_type _type;
662 const stored_type _t;
663};
664
665template<typename T>
666class value<typed<T>> : public value<T> {
667public:
668 value(const typed<T> & args)
669: value<T>(args.type, args.value) {
670 }
671};
672
674 bool _enabled = true;
675public:
676 value_list(description d) : _description(std::move(d))
677 {}
678 value_list(value_list&&) = default;
679 virtual ~value_list() {}
680
681 virtual size_t size() const = 0;
682
683 virtual void types(data_type *) const = 0;
684 virtual void values(net::packed<uint64_t> *) const = 0;
685
686 const description& desc() const {
687 return _description;
688 }
689
690 bool empty() const {
691 return size() == 0;
692 }
693
694 bool is_enabled() const {
695 return _enabled;
696 }
697
698 void set_enabled(bool b) {
699 _enabled = b;
700 }
701private:
702 description _description;
703};
704
705template<typename ... Args>
706class values_impl: public value_list {
707public:
708 static const size_t num_values = sizeof...(Args);
709
710 values_impl(description d, Args&& ...args)
711 : value_list(std::move(d))
712 , _values(std::forward<Args>(args)...)
713 {}
714
715 values_impl(values_impl<Args...>&& a) = default;
716 values_impl(const values_impl<Args...>& a) = default;
717
718 size_t size() const override {
719 return num_values;
720 }
721 void types(data_type * p) const override {
722 unpack(_values, [p](Args... args) {
723 std::initializer_list<data_type> tmp = { args... };
724 std::copy(tmp.begin(), tmp.end(), p);
725 });
726 }
727 void values(net::packed<uint64_t> * p) const override {
728 unpack(_values, [p](Args... args) {
729 std::initializer_list<uint64_t> tmp = { args... };
730 std::copy(tmp.begin(), tmp.end(), p);
731 });
732 }
733private:
734 template<typename _Op>
735 void unpack(const std::tuple<Args...>& t, _Op&& op) const {
736 do_unpack(t, std::index_sequence_for<Args...> {}, std::forward<_Op>(op));
737 }
738
739 template<size_t ...S, typename _Op>
740 void do_unpack(const std::tuple<Args...>& t, const std::index_sequence<S...> &, _Op&& op) const {
741 op(std::get<S>(t)...);
742 }
743
744 std::tuple < Args... > _values;
745};
746
747void add_polled(const type_instance_id &, const shared_ptr<value_list> &, bool enabled = true);
748
749typedef std::function<void()> notify_function;
750template<typename... _Args>
751static auto make_type_instance(description d, _Args && ... args) -> values_impl < decltype(value<_Args>(std::forward<_Args>(args)))... >
752{
753 return values_impl<decltype(value<_Args>(std::forward<_Args>(args)))...>(
754 std::move(d), value<_Args>(std::forward<_Args>(args))...);
755}
760template<typename ... _Args>
761[[deprecated("Use the metrics layer")]] static type_instance_id add_polled_metric(const plugin_id & plugin,
762 const plugin_instance_id & plugin_instance, const type_id & type,
763 const scollectd::type_instance & type_instance, _Args&& ... args) {
764 return add_polled_metric(plugin, plugin_instance, type, type_instance, description(),
765 std::forward<_Args>(args)...);
766}
771template<typename ... _Args>
772[[deprecated("Use the metrics layer")]] static type_instance_id add_polled_metric(const plugin_id & plugin,
773 const plugin_instance_id & plugin_instance, const type_id & type,
774 const scollectd::type_instance & type_instance, description d, _Args&& ... args) {
775 return add_polled_metric(
776 type_instance_id(plugin, plugin_instance, type, type_instance), std::move(d),
777 std::forward<_Args>(args)...);
778}
779template<typename ... _Args>
780static future<> send_explicit_metric(const plugin_id & plugin,
781 const plugin_instance_id & plugin_instance, const type_id & type,
782 const scollectd::type_instance & type_instance, _Args&& ... args) {
783 return send_explicit_metric(
784 type_instance_id(plugin, plugin_instance, type, type_instance),
785 std::forward<_Args>(args)...);
786}
787template<typename ... _Args>
788static notify_function create_explicit_metric(const plugin_id & plugin,
789 const plugin_instance_id & plugin_instance, const type_id & type,
790 const scollectd::type_instance & type_instance, _Args&& ... args) {
791 return create_explicit_metric(
792 type_instance_id(plugin, plugin_instance, type, type_instance),
793 std::forward<_Args>(args)...);
794}
795
796seastar::metrics::impl::metric_id to_metrics_id(const type_instance_id & id);
801template<typename Arg>
802[[deprecated("Use the metrics layer")]] static type_instance_id add_polled_metric(const type_instance_id & id, description d,
803 Arg&& arg, bool enabled = true) {
804 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);
805 return id;
806}
811template<typename Arg>
812[[deprecated("Use the metrics layer")]] static type_instance_id add_polled_metric(const type_instance_id & id,
813 Arg&& arg) {
814 return std::move(add_polled_metric(id, description(), std::forward<Arg>(arg)));
815}
816
821template<typename Args>
822[[deprecated("Use the metrics layer")]] static type_instance_id add_disabled_polled_metric(const type_instance_id & id, description d,
823 Args&& arg) {
824 return add_polled_metric(id, d, std::forward<Args>(arg), false);
825}
826
827template<typename Args>
828static type_instance_id add_disabled_polled_metric(const type_instance_id & id,
829 Args&& args) {
830 return add_disabled_polled_metric(id, description(), std::forward<Args>(args));
831}
832
833template<typename ... Args>
834static type_instance_id add_disabled_polled_metric(const type_instance_id & id,
835 Args&& ... args) {
836 return add_disabled_polled_metric(id, description(), std::forward<Args>(args)...);
837}
838
839// "Explicit" metric sends. Sends a single value list as a message.
840// Obviously not super efficient either. But maybe someone needs it sometime.
841template<typename ... _Args>
842static future<> send_explicit_metric(const type_instance_id & id,
843 _Args&& ... args) {
844 return send_metric(id, make_type_instance(std::forward<_Args>(args)...));
845}
846template<typename ... _Args>
847static notify_function create_explicit_metric(const type_instance_id & id,
848 _Args&& ... args) {
849 auto list = make_type_instance(std::forward<_Args>(args)...);
850 return [id, list=std::move(list)]() {
851 send_metric(id, list);
852 };
853}
854
855template<typename... Args>
856typed_value::typed_value(const type_id& tid, const scollectd::type_instance& ti, description d, Args&&... args)
857 : _type_id(tid)
858 , _type_instance(ti)
859 , _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)...)))
860{}
861
862// Send a message packet (string)
863future<> send_notification(const type_instance_id & id, const sstring & msg);
864}
865
866}
A representation of a possibly not-yet-computed value.
Definition: future.hh:1240
Human-readable description of a metric/group.
Definition: metrics.hh:133
Definition: metrics_api.hh:105
Definition: program-options.hh:292
Definition: scollectd.hh:421
Definition: scollectd.hh:303
Definition: scollectd.hh:673
Definition: scollectd.hh:583
Definition: scollectd.hh:706
future< uint64_t > file_size(std::string_view name) noexcept
sstring metric_type_def
Definition: metrics.hh:113
sstring metric_name_type
Definition: metrics.hh:114
sstring instance_id_type
Definition: metrics.hh:115
header file for metric API layer (like prometheus or collectd)
sstring group_name_type
Definition: metrics_registration.hh:64
static type_instance_id add_polled_metric(const plugin_id &plugin, const plugin_instance_id &plugin_instance, const type_id &type, const scollectd::type_instance &type_instance, _Args &&... args)
Definition: scollectd.hh:761
typed_value_impl< known_type::total_bytes > total_bytes
Definition: scollectd.hh:527
static type_instance_id add_disabled_polled_metric(const type_instance_id &id, description d, Args &&arg)
Definition: scollectd.hh:822
Definition: scollectd.hh:547
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
STL namespace.
Definition: scollectd.hh:544
Definition: scollectd.hh:354
program_options::value< std::string > collectd_hostname
Definition: scollectd.hh:369
program_options::value< unsigned > collectd_poll_period
Poll period (ms).
Definition: scollectd.hh:367
program_options::value< std::string > collectd_address
Address to send/broadcast metrics to.
Definition: scollectd.hh:362
program_options::value< bool > collectd
Enable collectd daemon.
Definition: scollectd.hh:358
Definition: scollectd.hh:393
Definition: scollectd.hh:506
Definition: scollectd.hh:443
typed_value(const type_id &tid, const scollectd::type_instance &ti, description, Args &&... args)
Definition: scollectd.hh:856
Definition: scollectd.hh:279
Definition: scollectd.hh:586
Definition: unaligned.hh:58