]>
Commit | Line | Data |
---|---|---|
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 | #include <functional> | |
23 | #include <unordered_map> | |
24 | #include <forward_list> | |
25 | #include <utility> | |
26 | #include <string> | |
27 | #include <map> | |
28 | #include <iostream> | |
29 | #include <unordered_map> | |
30 | ||
31 | #include <seastar/core/seastar.hh> | |
32 | #include <seastar/core/scollectd_api.hh> | |
33 | #include <seastar/core/metrics_api.hh> | |
34 | #include <seastar/core/byteorder.hh> | |
35 | #include <seastar/core/print.hh> | |
36 | ||
37 | #include "core/scollectd-impl.hh" | |
38 | ||
39 | namespace seastar { | |
40 | ||
41 | void scollectd::type_instance_id::truncate(sstring& field, const char* field_desc) { | |
42 | if (field.size() > max_collectd_field_text_len) { | |
43 | auto suffix_len = std::ceil(std::log10(++_next_truncated_idx)) + 1; | |
44 | sstring new_field(seastar::format( | |
45 | "{}~{:d}", sstring(field.data(), max_collectd_field_text_len - suffix_len), _next_truncated_idx)); | |
46 | ||
47 | logger.warn("Truncating \"{}\" to {} chars: \"{}\" -> \"{}\"", field_desc, max_collectd_field_text_len, field, | |
48 | new_field); | |
49 | field = std::move(new_field); | |
50 | } | |
51 | } | |
52 | ||
53 | bool scollectd::type_instance_id::operator<( | |
54 | const scollectd::type_instance_id& id2) const { | |
55 | auto& id1 = *this; | |
56 | return std::tie(id1.plugin(), id1.plugin_instance(), id1.type(), | |
57 | id1.type_instance()) | |
58 | < std::tie(id2.plugin(), id2.plugin_instance(), id2.type(), | |
59 | id2.type_instance()); | |
60 | } | |
61 | bool scollectd::type_instance_id::operator==( | |
62 | const scollectd::type_instance_id & id2) const { | |
63 | auto& id1 = *this; | |
64 | return std::tie(id1.plugin(), id1.plugin_instance(), id1.type(), | |
65 | id1.type_instance()) | |
66 | == std::tie(id2.plugin(), id2.plugin_instance(), id2.type(), | |
67 | id2.type_instance()); | |
68 | } | |
69 | ||
70 | namespace scollectd { | |
71 | ||
72 | ::seastar::logger logger("scollectd"); | |
73 | thread_local unsigned type_instance_id::_next_truncated_idx = 0; | |
74 | ||
75 | registration::~registration() { | |
76 | unregister(); | |
77 | } | |
78 | ||
79 | registration::registration(const type_instance_id& id) | |
80 | : _id(id), _impl(seastar::metrics::impl::get_local_impl()) { | |
81 | } | |
82 | ||
83 | registration::registration(type_instance_id&& id) | |
84 | : _id(std::move(id)), _impl(seastar::metrics::impl::get_local_impl()) { | |
85 | } | |
86 | ||
87 | seastar::metrics::impl::metric_id to_metrics_id(const type_instance_id & id) { | |
88 | return seastar::metrics::impl::metric_id(id.plugin(), id.type_instance(), | |
89 | {{seastar::metrics::shard_label.name(), seastar::metrics::impl::shard()}}); | |
90 | } | |
91 | ||
92 | ||
93 | const plugin_instance_id per_cpu_plugin_instance("#cpu"); | |
94 | ||
95 | static const size_t payload_size = 1024; | |
96 | ||
97 | enum class part_type : uint16_t { | |
98 | Host = 0x0000, // The name of the host to associate with subsequent data values | |
99 | Time = 0x0001, // Time Numeric The timestamp to associate with subsequent data values, unix time format (seconds since epoch) | |
100 | TimeHr = 0x0008, // Time (high resolution) Numeric The timestamp to associate with subsequent data values. Time is defined in 2–30 seconds since epoch. New in Version 5.0. | |
101 | Plugin = 0x0002, // Plugin String The plugin name to associate with subsequent data values, e.g. "cpu" | |
102 | PluginInst = 0x0003, // Plugin instance String The plugin instance name to associate with subsequent data values, e.g. "1" | |
103 | Type = 0x0004, // Type String The type name to associate with subsequent data values, e.g. "cpu" | |
104 | TypeInst = 0x0005, // Type instance String The type instance name to associate with subsequent data values, e.g. "idle" | |
105 | Values = 0x0006, // Values other Data values, see above | |
106 | Interval = 0x0007, // Interval Numeric Interval used to set the "step" when creating new RRDs unless rrdtool plugin forces StepSize. Also used to detect values that have timed out. | |
107 | IntervalHr = 0x0009, // Interval (high resolution) Numeric The interval in which subsequent data values are collected. The interval is given in 2–30 seconds. New in Version 5.0. | |
108 | Message = 0x0100, // Message (notifications) String | |
109 | Severity = 0x0101, // Severity Numeric | |
110 | Signature = 0x0200, // Signature (HMAC-SHA-256) other (todo) | |
111 | Encryption = 0x0210, // Encryption (AES-256/OFB | |
112 | }; | |
113 | ||
114 | // "Time is defined in 2^–30 seconds since epoch. New in Version 5.0." | |
115 | typedef std::chrono::duration<uint64_t, std::ratio<1, 0x40000000>> collectd_hres_duration; | |
116 | ||
117 | // yet another writer type, this one to construct collectd network | |
118 | // protocol data. | |
119 | struct cpwriter { | |
120 | typedef std::array<char, payload_size> buffer_type; | |
121 | typedef buffer_type::iterator mark_type; | |
122 | typedef buffer_type::const_iterator const_mark_type; | |
123 | ||
124 | buffer_type _buf; | |
125 | mark_type _pos; | |
126 | bool _overflow = false; | |
127 | ||
128 | std::unordered_map<uint16_t, sstring> _cache; | |
129 | ||
130 | cpwriter() | |
131 | : _pos(_buf.begin()) { | |
132 | } | |
133 | mark_type mark() const { | |
134 | return _pos; | |
135 | } | |
136 | bool overflow() const { | |
137 | return _overflow; | |
138 | } | |
139 | void reset(mark_type m) { | |
140 | _pos = m; | |
141 | _overflow = false; | |
142 | } | |
143 | size_t size() const { | |
144 | return std::distance(_buf.begin(), const_mark_type(_pos)); | |
145 | } | |
146 | bool empty() const { | |
147 | return _pos == _buf.begin(); | |
148 | } | |
149 | void clear() { | |
150 | reset(_buf.begin()); | |
151 | _cache.clear(); | |
152 | _overflow = false; | |
153 | } | |
154 | const char * data() const { | |
155 | return &_buf.at(0); | |
156 | } | |
157 | char * data() { | |
158 | return &_buf.at(0); | |
159 | } | |
160 | cpwriter& check(size_t sz) { | |
161 | size_t av = std::distance(_pos, _buf.end()); | |
162 | _overflow |= av < sz; | |
163 | return *this; | |
164 | } | |
165 | ||
166 | sstring get_type_instance(const seastar::metrics::impl::metric_id & id) { | |
167 | if (id.labels().empty()) { | |
168 | return id.name(); | |
169 | } | |
170 | sstring res = id.name(); | |
171 | for (auto i : id.labels()) { | |
172 | if (i.first != seastar::metrics::shard_label.name()) { | |
173 | res += "-" + i.second; | |
174 | } | |
175 | } | |
176 | return res; | |
177 | } | |
178 | explicit operator bool() const { | |
179 | return !_overflow; | |
180 | } | |
181 | bool operator!() const { | |
182 | return !operator bool(); | |
183 | } | |
184 | template<typename _Iter> | |
185 | cpwriter & write(_Iter s, _Iter e) { | |
186 | if (check(std::distance(s, e))) { | |
187 | _pos = std::copy(s, e, _pos); | |
188 | } | |
189 | return *this; | |
190 | } | |
191 | template<typename T> | |
192 | typename std::enable_if<std::is_integral<T>::value, cpwriter &>::type write( | |
193 | const T & t) { | |
194 | T tmp = net::hton(t); | |
195 | auto * p = reinterpret_cast<const uint8_t *>(&tmp); | |
196 | auto * e = p + sizeof(T); | |
197 | write(p, e); | |
198 | return *this; | |
199 | } | |
200 | template<typename T> | |
201 | typename std::enable_if<std::is_integral<T>::value, cpwriter &>::type write_le(const T & t) { | |
202 | T tmp = cpu_to_le(t); | |
203 | auto * p = reinterpret_cast<const uint8_t *>(&tmp); | |
204 | auto * e = p + sizeof(T); | |
205 | write(p, e); | |
206 | return *this; | |
207 | } | |
208 | void write_value(const seastar::metrics::impl::metric_value& v) { | |
209 | switch (v.type()) { | |
210 | case data_type::GAUGE: { | |
211 | double tmpd = v.d(); | |
212 | uint64_t tmpi; | |
213 | std::copy_n(reinterpret_cast<const char*>(&tmpd), 8, reinterpret_cast<char*>(&tmpi)); | |
214 | write_le(tmpi); | |
215 | break; | |
216 | } | |
217 | case data_type::COUNTER: | |
218 | case data_type::DERIVE: | |
219 | case data_type::ABSOLUTE: | |
220 | write(v.ui()); // big endian | |
221 | break; | |
222 | default: | |
223 | assert(0); | |
224 | } | |
225 | } | |
226 | cpwriter & write(const sstring & s) { | |
227 | write(s.begin(), s.end() + 1); // include \0 | |
228 | return *this; | |
229 | } | |
230 | cpwriter & put(part_type type, const sstring & s) { | |
231 | write(uint16_t(type)); | |
232 | write(uint16_t(4 + s.size() + 1)); // include \0 | |
233 | write(s); // include \0 | |
234 | return *this; | |
235 | } | |
236 | cpwriter & put_cached(part_type type, const sstring & s) { | |
237 | auto & cached = _cache[uint16_t(type)]; | |
238 | if (cached != s) { | |
239 | put(type, s); | |
240 | cached = s; | |
241 | } | |
242 | return *this; | |
243 | } | |
244 | template<typename T> | |
245 | typename std::enable_if<std::is_integral<T>::value, cpwriter &>::type put( | |
246 | part_type type, T t) { | |
247 | write(uint16_t(type)); | |
248 | write(uint16_t(4 + sizeof(t))); | |
249 | write(t); | |
250 | return *this; | |
251 | } | |
252 | cpwriter & put(part_type type, const value_list & v) { | |
253 | auto s = v.size(); | |
254 | auto sz = 6 + s + s * sizeof(uint64_t); | |
255 | if (check(sz)) { | |
256 | write(uint16_t(type)); | |
257 | write(uint16_t(sz)); | |
258 | write(uint16_t(s)); | |
259 | v.types(reinterpret_cast<data_type *>(&(*_pos))); | |
260 | _pos += s; | |
261 | v.values(reinterpret_cast<net::packed<uint64_t> *>(&(*_pos))); | |
262 | _pos += s * sizeof(uint64_t); | |
263 | } | |
264 | return *this; | |
265 | } | |
266 | ||
267 | cpwriter & put(part_type type, const seastar::metrics::impl::metric_value & v) { | |
268 | auto sz = 7 + sizeof(uint64_t); | |
269 | if (check(sz)) { | |
270 | write(uint16_t(type)); | |
271 | write(uint16_t(sz)); | |
272 | write(uint16_t(1)); | |
273 | write(static_cast<uint8_t>(v.type())); | |
274 | write_value(v); | |
275 | } | |
276 | return *this; | |
277 | } | |
278 | cpwriter & put(const sstring & host, const seastar::metrics::impl::metric_id & id, const type_id& type) { | |
279 | const auto ts = std::chrono::system_clock::now().time_since_epoch(); | |
280 | const auto lrts = | |
281 | std::chrono::duration_cast<std::chrono::seconds>(ts).count(); | |
282 | ||
283 | put_cached(part_type::Host, host); | |
284 | put(part_type::Time, uint64_t(lrts)); | |
285 | // Seems hi-res timestamp does not work very well with | |
286 | // at the very least my default collectd in fedora (or I did it wrong?) | |
287 | // Use lo-res ts for now, it is probably quite sufficient. | |
288 | put_cached(part_type::Plugin, id.group_name()); | |
289 | // Optional | |
290 | put_cached(part_type::PluginInst, | |
291 | id.instance_id() == per_cpu_plugin_instance ? | |
292 | to_sstring(this_shard_id()) : id.instance_id()); | |
293 | put_cached(part_type::Type, type); | |
294 | // Optional | |
295 | put_cached(part_type::TypeInst, get_type_instance(id)); | |
296 | return *this; | |
297 | } | |
298 | cpwriter & put(const sstring & host, | |
299 | const duration & period, | |
300 | const type_instance_id & id, const value_list & v) { | |
301 | const auto ps = std::chrono::duration_cast<collectd_hres_duration>( | |
302 | period).count(); | |
303 | put(host, to_metrics_id(id), id.type()); | |
304 | put(part_type::Values, v); | |
305 | if (ps != 0) { | |
306 | put(part_type::IntervalHr, ps); | |
307 | } | |
308 | return *this; | |
309 | } | |
310 | ||
311 | cpwriter & put(const sstring & host, | |
312 | const duration & period, | |
313 | const type_id& type, | |
314 | const seastar::metrics::impl::metric_id & id, const seastar::metrics::impl::metric_value & v) { | |
315 | const auto ps = std::chrono::duration_cast<collectd_hres_duration>( | |
316 | period).count(); | |
317 | put(host, id, type); | |
318 | put(part_type::Values, v); | |
319 | if (ps != 0) { | |
320 | put(part_type::IntervalHr, ps); | |
321 | } | |
322 | return *this; | |
323 | } | |
324 | }; | |
325 | ||
326 | void impl::add_polled(const type_instance_id & id, | |
327 | const shared_ptr<value_list> & values, bool enable) { | |
328 | // do nothing | |
329 | // add_polled is now implemented on the metrics layer | |
330 | ||
331 | } | |
332 | ||
333 | void impl::remove_polled(const type_instance_id & id) { | |
334 | seastar::metrics::impl::unregister_metric(to_metrics_id(id)); | |
335 | } | |
336 | ||
337 | // explicitly send a type_instance value list (outside polling) | |
338 | future<> impl::send_metric(const type_instance_id & id, | |
339 | const value_list & values) { | |
340 | if (values.empty()) { | |
341 | return make_ready_future(); | |
342 | } | |
343 | cpwriter out; | |
344 | out.put(_host, duration(), id, values); | |
345 | return _chan.send(_addr, net::packet(out.data(), out.size())); | |
346 | } | |
347 | ||
348 | future<> impl::send_notification(const type_instance_id & id, | |
349 | const sstring & msg) { | |
350 | cpwriter out; | |
351 | out.put(_host, to_metrics_id(id), id.type()); | |
352 | out.put(part_type::Message, msg); | |
353 | return _chan.send(_addr, net::packet(out.data(), out.size())); | |
354 | } | |
355 | ||
356 | // initiates actual value polling -> send to target "loop" | |
357 | void impl::start(const sstring & host, const ipv4_addr & addr, const duration period) { | |
358 | _period = period; | |
359 | _addr = addr; | |
360 | _host = host; | |
361 | _chan = make_udp_channel(); | |
362 | _timer.set_callback(std::bind(&impl::run, this)); | |
363 | ||
364 | // dogfood ourselves | |
365 | namespace sm = seastar::metrics; | |
366 | ||
367 | _metrics.add_group("scollectd", { | |
368 | // total_bytes value:DERIVE:0:U | |
369 | sm::make_derive("total_bytes_sent", sm::description("total bytes sent"), _bytes), | |
370 | // total_requests value:DERIVE:0:U | |
371 | sm::make_derive("total_requests", sm::description("total requests"), _num_packets), | |
372 | // latency value:GAUGE:0:U | |
373 | sm::make_gauge("latency", sm::description("avrage latency"), _avg), | |
374 | // total_time_in_ms value:DERIVE:0:U | |
375 | sm::make_derive("total_time_in_ms", sm::description("total time in milliseconds"), _millis), | |
376 | // total_values value:DERIVE:0:U | |
377 | sm::make_gauge("total_values", sm::description("current number of values reported"), [this] {return values().size();}), | |
378 | // records value:GAUGE:0:U | |
379 | sm::make_gauge("records", sm::description("number of records reported"), [this] {return values().size();}), | |
380 | }); | |
381 | ||
382 | // FIXME: future is discarded | |
383 | (void)send_notification( | |
384 | type_instance_id("scollectd", per_cpu_plugin_instance, | |
385 | "network"), "daemon started"); | |
386 | arm(); | |
387 | } | |
388 | ||
389 | void impl::stop() { | |
390 | _timer.cancel(); | |
391 | _metrics.clear(); | |
392 | } | |
393 | ||
394 | ||
395 | void impl::arm() { | |
396 | if (_period != duration()) { | |
397 | _timer.arm(_period); | |
398 | } | |
399 | } | |
400 | ||
401 | void impl::run() { | |
402 | typedef size_t metric_family_id; | |
403 | typedef seastar::metrics::impl::value_vector::iterator value_iterator; | |
404 | typedef seastar::metrics::impl::metric_metadata_vector::iterator metadata_iterator; | |
405 | typedef std::tuple<metric_family_id, metadata_iterator, value_iterator, type_id, cpwriter> context; | |
406 | ||
407 | auto ctxt = make_lw_shared<context>(); | |
408 | foreign_ptr<shared_ptr<seastar::metrics::impl::values_copy>> vals = seastar::metrics::impl::get_values(); | |
409 | ||
410 | // note we're doing this unsynced since we assume | |
411 | // all registrations to this instance will be done on the | |
412 | // same cpu, and without interuptions (no wait-states) | |
413 | ||
414 | auto& values = vals->values; | |
415 | auto metadata = vals->metadata; | |
416 | std::get<metric_family_id>(*ctxt) = 0; | |
417 | if (values.size() > 0) { | |
418 | std::get<value_iterator>(*ctxt) = values[0].begin(); | |
419 | std::get<metadata_iterator>(*ctxt) = metadata->at(0).metrics.begin(); | |
420 | std::get<type_id>(*ctxt) = metadata->at(0).mf.inherit_type; | |
421 | } | |
422 | ||
423 | auto stop_when = [ctxt, metadata]() { | |
424 | auto done = std::get<metric_family_id>(*ctxt) == metadata->size(); | |
425 | return done; | |
426 | }; | |
427 | // append as many values as we can fit into a packet (1024 bytes) | |
428 | auto send_packet = [this, ctxt, &values, metadata]() mutable { | |
429 | auto start = steady_clock_type::now(); | |
430 | auto& mf = std::get<metric_family_id>(*ctxt); | |
431 | auto & md_iterator = std::get<metadata_iterator>(*ctxt); | |
432 | auto & i = std::get<value_iterator>(*ctxt); | |
433 | auto & out = std::get<cpwriter>(*ctxt); | |
434 | ||
435 | out.clear(); | |
436 | ||
437 | bool out_of_space = false; | |
438 | while (!out_of_space && mf < values.size()) { | |
439 | while (i != values[mf].end()) { | |
440 | if (i->type() == seastar::metrics::impl::data_type::HISTOGRAM) { | |
441 | ++i; | |
442 | ++md_iterator; | |
443 | continue; | |
444 | } | |
445 | auto m = out.mark(); | |
446 | out.put(_host, _period, std::get<type_id>(*ctxt), md_iterator->id, *i); | |
447 | if (!out) { | |
448 | out.reset(m); | |
449 | out_of_space = true; | |
450 | break; | |
451 | } | |
452 | ++i; | |
453 | ++md_iterator; | |
454 | } | |
455 | if (out_of_space) { | |
456 | break; | |
457 | } | |
458 | ++mf; | |
459 | if (mf < values.size()) { | |
460 | i = values[mf].begin(); | |
461 | md_iterator = metadata->at(mf).metrics.begin(); | |
462 | std::get<type_id>(*ctxt) = metadata->at(mf).mf.inherit_type; | |
463 | } | |
464 | } | |
465 | if (out.empty()) { | |
466 | return make_ready_future(); | |
467 | } | |
468 | return _chan.send(_addr, net::packet(out.data(), out.size())).then([start, ctxt, this]() { | |
469 | auto & out = std::get<cpwriter>(*ctxt); | |
470 | auto now = steady_clock_type::now(); | |
471 | // dogfood stats | |
472 | ++_num_packets; | |
473 | _millis += std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count(); | |
474 | _bytes += out.size(); | |
475 | _avg = double(_millis) / _num_packets; | |
476 | }).then_wrapped([] (auto&& f) { | |
477 | try { | |
478 | f.get(); | |
479 | } catch (std::exception & ex) { | |
480 | std::cout << "send failed: " << ex.what() << std::endl; | |
481 | } catch (...) { | |
482 | std::cout << "send failed: - unknown exception" << std::endl; | |
483 | } | |
484 | }); | |
485 | }; | |
486 | // No need to wait for future. | |
487 | // The caller has to call impl::stop() to synchronize. | |
488 | (void)do_until(stop_when, send_packet).finally([this, vals = std::move(vals)]() mutable { | |
489 | arm(); | |
490 | }); | |
491 | } | |
492 | ||
493 | std::vector<type_instance_id> impl::get_instance_ids() const { | |
494 | std::vector<type_instance_id> res; | |
495 | for (auto&& v: values()) { | |
496 | // Need to check for empty value_list, since unreg is two-stage. | |
497 | // Not an issue for most uses, but unit testing etc that would like | |
498 | // fully deterministic operation here would like us to only return | |
499 | // actually active ids | |
500 | for (auto i : v.second) { | |
501 | if (i.second) { | |
502 | res.emplace_back(i.second->get_id(), v.second.info().inherit_type); | |
503 | } | |
504 | } | |
505 | } | |
506 | return res; | |
507 | } | |
508 | ||
509 | void add_polled(const type_instance_id & id, | |
510 | const shared_ptr<value_list> & values, bool enabled) { | |
511 | get_impl().add_polled(id, values, enabled); | |
512 | } | |
513 | ||
514 | void remove_polled_metric(const type_instance_id & id) { | |
515 | get_impl().remove_polled(id); | |
516 | } | |
517 | ||
518 | future<> send_notification(const type_instance_id & id, | |
519 | const sstring & msg) { | |
520 | return get_impl().send_notification(id, msg); | |
521 | } | |
522 | ||
523 | future<> send_metric(const type_instance_id & id, | |
524 | const value_list & values) { | |
525 | return get_impl().send_metric(id, values); | |
526 | } | |
527 | ||
528 | void configure(const boost::program_options::variables_map & opts) { | |
529 | bool enable = opts["collectd"].as<bool>(); | |
530 | if (!enable) { | |
531 | return; | |
532 | } | |
533 | auto addr = ipv4_addr(opts["collectd-address"].as<std::string>()); | |
534 | auto period = std::chrono::milliseconds(opts["collectd-poll-period"].as<unsigned>()); | |
535 | ||
536 | auto host = (opts["collectd-hostname"].as<std::string>() == "") | |
537 | ? seastar::metrics::impl::get_local_impl()->get_config().hostname | |
538 | : sstring(opts["collectd-hostname"].as<std::string>()); | |
539 | ||
540 | // Now create send loops on each cpu | |
541 | for (unsigned c = 0; c < smp::count; c++) { | |
542 | // FIXME: future is discarded | |
543 | (void)smp::submit_to(c, [=] () { | |
544 | get_impl().start(host, addr, period); | |
545 | }); | |
546 | } | |
547 | } | |
548 | ||
549 | boost::program_options::options_description get_options_description() { | |
550 | namespace bpo = boost::program_options; | |
551 | bpo::options_description opts("COLLECTD options"); | |
552 | opts.add_options()("collectd", bpo::value<bool>()->default_value(false), | |
553 | "enable collectd daemon")("collectd-address", | |
554 | bpo::value<std::string>()->default_value("239.192.74.66:25826"), | |
555 | "address to send/broadcast metrics to")("collectd-poll-period", | |
556 | bpo::value<unsigned>()->default_value(1000), | |
557 | "poll period - frequency of sending counter metrics (default: 1000ms, 0 disables)")( | |
558 | "collectd-hostname", | |
559 | bpo::value<std::string>()->default_value(""), | |
560 | "Deprecated option, use metrics-hostname instead"); | |
561 | return opts; | |
562 | } | |
563 | ||
564 | static seastar::metrics::impl::register_ref get_register(const scollectd::type_instance_id& i) { | |
565 | seastar::metrics::impl::metric_id id = to_metrics_id(i); | |
566 | return seastar::metrics::impl::get_value_map().at(id.full_name()).at(id.labels()); | |
567 | } | |
568 | ||
569 | std::vector<collectd_value> get_collectd_value( | |
570 | const scollectd::type_instance_id& id) { | |
571 | std::vector<collectd_value> vals; | |
572 | const seastar::metrics::impl::registered_metric& val = *get_register(id); | |
573 | vals.push_back(val()); | |
574 | return vals; | |
575 | } | |
576 | ||
577 | std::vector<scollectd::type_instance_id> get_collectd_ids() { | |
578 | return get_impl().get_instance_ids(); | |
579 | } | |
580 | ||
581 | bool is_enabled(const scollectd::type_instance_id& id) { | |
582 | return get_register(id)->is_enabled(); | |
583 | } | |
584 | ||
585 | void enable(const scollectd::type_instance_id& id, bool enable) { | |
586 | get_register(id)->set_enabled(enable); | |
587 | } | |
588 | ||
589 | type_instance_id plugin_instance_metrics::add_impl(const typed_value& v) { | |
590 | type_instance_id id(_plugin_id, _plugin_instance, v.type(), v.type_instance()); | |
591 | get_impl().add_polled(id, v.values()); | |
592 | return id; | |
593 | } | |
594 | ||
595 | void plugin_instance_metrics::add(const typed_value& v) { | |
596 | _registrations.emplace_back(add_impl(v)); | |
597 | } | |
598 | ||
599 | std::vector<type_instance_id> plugin_instance_metrics::bound_ids() const { | |
600 | std::vector<type_instance_id> res; | |
601 | res.reserve(_registrations.size()); | |
602 | std::transform(_registrations.begin(), _registrations.end(), std::back_inserter(res), [](const registration& r) { | |
603 | return r._id; | |
604 | }); | |
605 | return res; | |
606 | } | |
607 | ||
608 | type_id type_id_for(known_type t) { | |
609 | switch (t) { | |
610 | case known_type::absolute: | |
611 | return "absolute"; | |
612 | case known_type::backends: | |
613 | return "backends"; | |
614 | case known_type::bitrate: | |
615 | return "bitrate"; | |
616 | case known_type::blocked_clients: | |
617 | return "blocked_clients"; | |
618 | case known_type::bytes: | |
619 | return "bytes"; | |
620 | case known_type::cache_eviction: | |
621 | return "cache_eviction"; | |
622 | case known_type::cache_operation: | |
623 | return "cache_operation"; | |
624 | case known_type::cache_ratio: | |
625 | return "cache_ratio"; | |
626 | case known_type::cache_result: | |
627 | return "cache_result"; | |
628 | case known_type::cache_size: | |
629 | return "cache_size"; | |
630 | case known_type::capacity: | |
631 | return "capacity"; | |
632 | case known_type::changes_since_last_save: | |
633 | return "changes_since_last_save"; | |
634 | case known_type::charge: | |
635 | return "charge"; | |
636 | case known_type::clock_last_meas: | |
637 | return "clock_last_meas"; | |
638 | case known_type::clock_last_update: | |
639 | return "clock_last_update"; | |
640 | case known_type::clock_mode: | |
641 | return "clock_mode"; | |
642 | case known_type::clock_reachability: | |
643 | return "clock_reachability"; | |
644 | case known_type::clock_skew_ppm: | |
645 | return "clock_skew_ppm"; | |
646 | case known_type::clock_state: | |
647 | return "clock_state"; | |
648 | case known_type::clock_stratum: | |
649 | return "clock_stratum"; | |
650 | case known_type::compression: | |
651 | return "compression"; | |
652 | case known_type::compression_ratio: | |
653 | return "compression_ratio"; | |
654 | case known_type::connections: | |
655 | return "connections"; | |
656 | case known_type::conntrack: | |
657 | return "conntrack"; | |
658 | case known_type::contextswitch: | |
659 | return "contextswitch"; | |
660 | case known_type::count: | |
661 | return "count"; | |
662 | case known_type::counter: | |
663 | return "counter"; | |
664 | case known_type::cpu: | |
665 | return "cpu"; | |
666 | case known_type::cpufreq: | |
667 | return "cpufreq"; | |
668 | case known_type::current: | |
669 | return "current"; | |
670 | case known_type::current_connections: | |
671 | return "current_connections"; | |
672 | case known_type::current_sessions: | |
673 | return "current_sessions"; | |
674 | case known_type::delay: | |
675 | return "delay"; | |
676 | case known_type::derive: | |
677 | return "derive"; | |
678 | case known_type::df: | |
679 | return "df"; | |
680 | case known_type::df_complex: | |
681 | return "df_complex"; | |
682 | case known_type::df_inodes: | |
683 | return "df_inodes"; | |
684 | case known_type::disk_io_time: | |
685 | return "disk_io_time"; | |
686 | case known_type::disk_latency: | |
687 | return "disk_latency"; | |
688 | case known_type::disk_merged: | |
689 | return "disk_merged"; | |
690 | case known_type::disk_octets: | |
691 | return "disk_octets"; | |
692 | case known_type::disk_ops: | |
693 | return "disk_ops"; | |
694 | case known_type::disk_ops_complex: | |
695 | return "disk_ops_complex"; | |
696 | case known_type::disk_time: | |
697 | return "disk_time"; | |
698 | case known_type::dns_answer: | |
699 | return "dns_answer"; | |
700 | case known_type::dns_notify: | |
701 | return "dns_notify"; | |
702 | case known_type::dns_octets: | |
703 | return "dns_octets"; | |
704 | case known_type::dns_opcode: | |
705 | return "dns_opcode"; | |
706 | case known_type::dns_qtype: | |
707 | return "dns_qtype"; | |
708 | case known_type::dns_qtype_cached: | |
709 | return "dns_qtype_cached"; | |
710 | case known_type::dns_query: | |
711 | return "dns_query"; | |
712 | case known_type::dns_question: | |
713 | return "dns_question"; | |
714 | case known_type::dns_rcode: | |
715 | return "dns_rcode"; | |
716 | case known_type::dns_reject: | |
717 | return "dns_reject"; | |
718 | case known_type::dns_request: | |
719 | return "dns_request"; | |
720 | case known_type::dns_resolver: | |
721 | return "dns_resolver"; | |
722 | case known_type::dns_response: | |
723 | return "dns_response"; | |
724 | case known_type::dns_transfer: | |
725 | return "dns_transfer"; | |
726 | case known_type::dns_update: | |
727 | return "dns_update"; | |
728 | case known_type::dns_zops: | |
729 | return "dns_zops"; | |
730 | case known_type::drbd_resource: | |
731 | return "drbd_resource"; | |
732 | case known_type::duration: | |
733 | return "duration"; | |
734 | case known_type::email_check: | |
735 | return "email_check"; | |
736 | case known_type::email_count: | |
737 | return "email_count"; | |
738 | case known_type::email_size: | |
739 | return "email_size"; | |
740 | case known_type::entropy: | |
741 | return "entropy"; | |
742 | case known_type::evicted_keys: | |
743 | return "evicted_keys"; | |
744 | case known_type::expired_keys: | |
745 | return "expired_keys"; | |
746 | case known_type::fanspeed: | |
747 | return "fanspeed"; | |
748 | case known_type::file_handles: | |
749 | return "file_handles"; | |
750 | case known_type::file_size: | |
751 | return "file_size"; | |
752 | case known_type::files: | |
753 | return "files"; | |
754 | case known_type::flow: | |
755 | return "flow"; | |
756 | case known_type::fork_rate: | |
757 | return "fork_rate"; | |
758 | case known_type::frequency: | |
759 | return "frequency"; | |
760 | case known_type::frequency_error: | |
761 | return "frequency_error"; | |
762 | case known_type::frequency_offset: | |
763 | return "frequency_offset"; | |
764 | case known_type::fscache_stat: | |
765 | return "fscache_stat"; | |
766 | case known_type::gauge: | |
767 | return "gauge"; | |
768 | case known_type::hash_collisions: | |
769 | return "hash_collisions"; | |
770 | case known_type::http_request_methods: | |
771 | return "http_request_methods"; | |
772 | case known_type::http_requests: | |
773 | return "http_requests"; | |
774 | case known_type::http_response_codes: | |
775 | return "http_response_codes"; | |
776 | case known_type::humidity: | |
777 | return "humidity"; | |
778 | case known_type::if_collisions: | |
779 | return "if_collisions"; | |
780 | case known_type::if_dropped: | |
781 | return "if_dropped"; | |
782 | case known_type::if_errors: | |
783 | return "if_errors"; | |
784 | case known_type::if_multicast: | |
785 | return "if_multicast"; | |
786 | case known_type::if_octets: | |
787 | return "if_octets"; | |
788 | case known_type::if_packets: | |
789 | return "if_packets"; | |
790 | case known_type::if_rx_errors: | |
791 | return "if_rx_errors"; | |
792 | case known_type::if_rx_octets: | |
793 | return "if_rx_octets"; | |
794 | case known_type::if_tx_errors: | |
795 | return "if_tx_errors"; | |
796 | case known_type::if_tx_octets: | |
797 | return "if_tx_octets"; | |
798 | case known_type::invocations: | |
799 | return "invocations"; | |
800 | case known_type::io_octets: | |
801 | return "io_octets"; | |
802 | case known_type::io_packets: | |
803 | return "io_packets"; | |
804 | case known_type::ipt_bytes: | |
805 | return "ipt_bytes"; | |
806 | case known_type::ipt_packets: | |
807 | return "ipt_packets"; | |
808 | case known_type::irq: | |
809 | return "irq"; | |
810 | case known_type::latency: | |
811 | return "latency"; | |
812 | case known_type::links: | |
813 | return "links"; | |
814 | case known_type::load: | |
815 | return "load"; | |
816 | case known_type::md_disks: | |
817 | return "md_disks"; | |
818 | case known_type::memory: | |
819 | return "memory"; | |
820 | case known_type::memory_lua: | |
821 | return "memory_lua"; | |
822 | case known_type::memory_throttle_count: | |
823 | return "memory_throttle_count"; | |
824 | case known_type::multimeter: | |
825 | return "multimeter"; | |
826 | case known_type::mutex_operations: | |
827 | return "mutex_operations"; | |
828 | case known_type::objects: | |
829 | return "objects"; | |
830 | case known_type::operations: | |
831 | return "operations"; | |
832 | case known_type::packets: | |
833 | return "packets"; | |
834 | case known_type::pending_operations: | |
835 | return "pending_operations"; | |
836 | case known_type::percent: | |
837 | return "percent"; | |
838 | case known_type::percent_bytes: | |
839 | return "percent_bytes"; | |
840 | case known_type::percent_inodes: | |
841 | return "percent_inodes"; | |
842 | case known_type::ping: | |
843 | return "ping"; | |
844 | case known_type::ping_droprate: | |
845 | return "ping_droprate"; | |
846 | case known_type::ping_stddev: | |
847 | return "ping_stddev"; | |
848 | case known_type::players: | |
849 | return "players"; | |
850 | case known_type::power: | |
851 | return "power"; | |
852 | case known_type::pressure: | |
853 | return "pressure"; | |
854 | case known_type::protocol_counter: | |
855 | return "protocol_counter"; | |
856 | case known_type::pubsub: | |
857 | return "pubsub"; | |
858 | case known_type::queue_length: | |
859 | return "queue_length"; | |
860 | case known_type::records: | |
861 | return "records"; | |
862 | case known_type::requests: | |
863 | return "requests"; | |
864 | case known_type::response_code: | |
865 | return "response_code"; | |
866 | case known_type::response_time: | |
867 | return "response_time"; | |
868 | case known_type::root_delay: | |
869 | return "root_delay"; | |
870 | case known_type::root_dispersion: | |
871 | return "root_dispersion"; | |
872 | case known_type::route_etx: | |
873 | return "route_etx"; | |
874 | case known_type::route_metric: | |
875 | return "route_metric"; | |
876 | case known_type::routes: | |
877 | return "routes"; | |
878 | case known_type::segments: | |
879 | return "segments"; | |
880 | case known_type::serial_octets: | |
881 | return "serial_octets"; | |
882 | case known_type::signal_noise: | |
883 | return "signal_noise"; | |
884 | case known_type::signal_power: | |
885 | return "signal_power"; | |
886 | case known_type::signal_quality: | |
887 | return "signal_quality"; | |
888 | case known_type::snr: | |
889 | return "snr"; | |
890 | case known_type::spl: | |
891 | return "spl"; | |
892 | case known_type::swap: | |
893 | return "swap"; | |
894 | case known_type::swap_io: | |
895 | return "swap_io"; | |
896 | case known_type::tcp_connections: | |
897 | return "tcp_connections"; | |
898 | case known_type::temperature: | |
899 | return "temperature"; | |
900 | case known_type::threads: | |
901 | return "threads"; | |
902 | case known_type::time_dispersion: | |
903 | return "time_dispersion"; | |
904 | case known_type::time_offset: | |
905 | return "time_offset"; | |
906 | case known_type::time_offset_ntp: | |
907 | return "time_offset_ntp"; | |
908 | case known_type::time_offset_rms: | |
909 | return "time_offset_rms"; | |
910 | case known_type::time_ref: | |
911 | return "time_ref"; | |
912 | case known_type::timeleft: | |
913 | return "timeleft"; | |
914 | case known_type::total_bytes: | |
915 | return "total_bytes"; | |
916 | case known_type::total_connections: | |
917 | return "total_connections"; | |
918 | case known_type::total_objects: | |
919 | return "total_objects"; | |
920 | case known_type::total_operations: | |
921 | return "total_operations"; | |
922 | case known_type::total_requests: | |
923 | return "total_requests"; | |
924 | case known_type::total_sessions: | |
925 | return "total_sessions"; | |
926 | case known_type::total_threads: | |
927 | return "total_threads"; | |
928 | case known_type::total_time_in_ms: | |
929 | return "total_time_in_ms"; | |
930 | case known_type::total_values: | |
931 | return "total_values"; | |
932 | case known_type::uptime: | |
933 | return "uptime"; | |
934 | case known_type::users: | |
935 | return "users"; | |
936 | case known_type::vcl: | |
937 | return "vcl"; | |
938 | case known_type::vcpu: | |
939 | return "vcpu"; | |
940 | case known_type::virt_cpu_total: | |
941 | return "virt_cpu_total"; | |
942 | case known_type::virt_vcpu: | |
943 | return "virt_vcpu"; | |
944 | case known_type::vmpage_action: | |
945 | return "vmpage_action"; | |
946 | case known_type::vmpage_faults: | |
947 | return "vmpage_faults"; | |
948 | case known_type::vmpage_io: | |
949 | return "vmpage_io"; | |
950 | case known_type::vmpage_number: | |
951 | return "vmpage_number"; | |
952 | case known_type::volatile_changes: | |
953 | return "volatile_changes"; | |
954 | case known_type::voltage: | |
955 | return "voltage"; | |
956 | case known_type::voltage_threshold: | |
957 | return "voltage_threshold"; | |
958 | case known_type::vs_memory: | |
959 | return "vs_memory"; | |
960 | case known_type::vs_processes: | |
961 | return "vs_processes"; | |
962 | case known_type::vs_threads: | |
963 | return "vs_threads"; | |
964 | default: | |
965 | throw std::invalid_argument("Unknown type"); | |
966 | } | |
967 | } | |
968 | ||
969 | metrics::impl::value_map get_value_map() { | |
970 | return metrics::impl::get_value_map(); | |
971 | } | |
972 | ||
973 | } | |
974 | ||
975 | } |