]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/src/core/metrics.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / seastar / src / core / metrics.cc
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#include <seastar/core/metrics.hh>
23#include <seastar/core/metrics_api.hh>
f67539c2 24#include <seastar/core/reactor.hh>
11fdf7f2
TL
25#include <boost/range/algorithm.hpp>
26#include <boost/algorithm/string.hpp>
27#include <boost/algorithm/string/replace.hpp>
28#include <boost/range/algorithm_ext/erase.hpp>
29
30namespace seastar {
31namespace metrics {
32
9f95a23c
TL
33double_registration::double_registration(std::string what): std::runtime_error(what) {}
34
11fdf7f2
TL
35metric_groups::metric_groups() noexcept : _impl(impl::create_metric_groups()) {
36}
37
38void metric_groups::clear() {
39 _impl = impl::create_metric_groups();
40}
41
42metric_groups::metric_groups(std::initializer_list<metric_group_definition> mg) : _impl(impl::create_metric_groups()) {
43 for (auto&& i : mg) {
44 add_group(i.name, i.metrics);
45 }
46}
47metric_groups& metric_groups::add_group(const group_name_type& name, const std::initializer_list<metric_definition>& l) {
48 _impl->add_group(name, l);
49 return *this;
50}
9f95a23c
TL
51metric_groups& metric_groups::add_group(const group_name_type& name, const std::vector<metric_definition>& l) {
52 _impl->add_group(name, l);
53 return *this;
54}
11fdf7f2
TL
55metric_group::metric_group() noexcept = default;
56metric_group::~metric_group() = default;
57metric_group::metric_group(const group_name_type& name, std::initializer_list<metric_definition> l) {
58 add_group(name, l);
59}
60
61metric_group_definition::metric_group_definition(const group_name_type& name, std::initializer_list<metric_definition> l) : name(name), metrics(l) {
62}
63
64metric_group_definition::~metric_group_definition() = default;
65
66metric_groups::~metric_groups() = default;
67metric_definition::metric_definition(metric_definition&& m) noexcept : _impl(std::move(m._impl)) {
68}
69
70metric_definition::~metric_definition() = default;
71
72metric_definition::metric_definition(impl::metric_definition_impl const& m) noexcept :
73 _impl(std::make_unique<impl::metric_definition_impl>(m)) {
74}
75
76bool label_instance::operator<(const label_instance& id2) const {
77 auto& id1 = *this;
78 return std::tie(id1.key(), id1.value())
79 < std::tie(id2.key(), id2.value());
80}
81
82bool label_instance::operator==(const label_instance& id2) const {
83 auto& id1 = *this;
84 return std::tie(id1.key(), id1.value())
85 == std::tie(id2.key(), id2.value());
86}
87
88
89static std::string get_hostname() {
90 char hostname[PATH_MAX];
91 gethostname(hostname, sizeof(hostname));
92 hostname[PATH_MAX-1] = '\0';
93 return hostname;
94}
95
96
97boost::program_options::options_description get_options_description() {
98 namespace bpo = boost::program_options;
99 bpo::options_description opts("Metrics options");
100 opts.add_options()(
101 "metrics-hostname",
102 bpo::value<std::string>()->default_value(get_hostname()),
103 "set the hostname used by the metrics, if not set, the local hostname will be used");
104 return opts;
105}
106
107future<> configure(const boost::program_options::variables_map & opts) {
108 impl::config c;
109 c.hostname = opts["metrics-hostname"].as<std::string>();
110 return smp::invoke_on_all([c] {
111 impl::get_local_impl()->set_config(c);
112 });
113}
114
115
116bool label_instance::operator!=(const label_instance& id2) const {
117 auto& id1 = *this;
118 return !(id1 == id2);
119}
120
121label shard_label("shard");
11fdf7f2
TL
122namespace impl {
123
124registered_metric::registered_metric(metric_id id, metric_function f, bool enabled) :
125 _f(f), _impl(get_local_impl()) {
126 _info.enabled = enabled;
127 _info.id = id;
128}
129
130metric_value metric_value::operator+(const metric_value& c) {
131 metric_value res(*this);
132 switch (_type) {
133 case data_type::HISTOGRAM:
f67539c2 134 std::get<histogram>(res.u) += std::get<histogram>(c.u);
11fdf7f2
TL
135 break;
136 default:
f67539c2 137 std::get<double>(res.u) += std::get<double>(c.u);
11fdf7f2
TL
138 break;
139 }
140 return res;
141}
142
143metric_definition_impl::metric_definition_impl(
144 metric_name_type name,
145 metric_type type,
146 metric_function f,
147 description d,
148 std::vector<label_instance> _labels)
149 : name(name), type(type), f(f)
150 , d(d), enabled(true) {
151 for (auto i: _labels) {
152 labels[i.key()] = i.value();
153 }
154 if (labels.find(shard_label.name()) == labels.end()) {
155 labels[shard_label.name()] = shard();
156 }
11fdf7f2
TL
157}
158
159metric_definition_impl& metric_definition_impl::operator ()(bool _enabled) {
160 enabled = _enabled;
161 return *this;
162}
163
164metric_definition_impl& metric_definition_impl::operator ()(const label_instance& label) {
165 labels[label.key()] = label.value();
166 return *this;
167}
168
f67539c2
TL
169metric_definition_impl& metric_definition_impl::set_type(const sstring& type_name) {
170 type.type_name = type_name;
171 return *this;
172}
173
11fdf7f2
TL
174std::unique_ptr<metric_groups_def> create_metric_groups() {
175 return std::make_unique<metric_groups_impl>();
176}
177
178metric_groups_impl::~metric_groups_impl() {
9f95a23c 179 for (const auto& i : _registration) {
11fdf7f2
TL
180 unregister_metric(i);
181 }
182}
183
184metric_groups_impl& metric_groups_impl::add_metric(group_name_type name, const metric_definition& md) {
185
186 metric_id id(name, md._impl->name, md._impl->labels);
187
f67539c2 188 get_local_impl()->add_registration(id, md._impl->type, md._impl->f, md._impl->d, md._impl->enabled);
11fdf7f2
TL
189
190 _registration.push_back(id);
191 return *this;
192}
193
194metric_groups_impl& metric_groups_impl::add_group(group_name_type name, const std::vector<metric_definition>& l) {
195 for (auto i = l.begin(); i != l.end(); ++i) {
196 add_metric(name, *(i->_impl.get()));
197 }
198 return *this;
199}
200
201metric_groups_impl& metric_groups_impl::add_group(group_name_type name, const std::initializer_list<metric_definition>& l) {
202 for (auto i = l.begin(); i != l.end(); ++i) {
203 add_metric(name, *i);
204 }
205 return *this;
206}
207
208bool metric_id::operator<(
209 const metric_id& id2) const {
210 return as_tuple() < id2.as_tuple();
211}
212
213static std::string safe_name(const sstring& name) {
214 auto rep = boost::replace_all_copy(boost::replace_all_copy(name, "-", "_"), " ", "_");
215 boost::remove_erase_if(rep, boost::is_any_of("+()"));
216 return rep;
217}
218
219sstring metric_id::full_name() const {
220 return safe_name(_group + "_" + _name);
221}
222
223bool metric_id::operator==(
224 const metric_id & id2) const {
225 return as_tuple() == id2.as_tuple();
226}
227
228// Unfortunately, metrics_impl can not be shared because it
229// need to be available before the first users (reactor) will call it
230
231shared_ptr<impl> get_local_impl() {
232 static thread_local auto the_impl = ::seastar::make_shared<impl>();
233 return the_impl;
234}
235void impl::remove_registration(const metric_id& id) {
236 auto i = get_value_map().find(id.full_name());
237 if (i != get_value_map().end()) {
238 auto j = i->second.find(id.labels());
239 if (j != i->second.end()) {
240 j->second = nullptr;
241 i->second.erase(j);
242 }
243 if (i->second.empty()) {
244 get_value_map().erase(i);
245 }
246 dirty();
247 }
248}
249
250void unregister_metric(const metric_id & id) {
251 get_local_impl()->remove_registration(id);
252}
253
254const value_map& get_value_map() {
255 return get_local_impl()->get_value_map();
256}
257
258foreign_ptr<values_reference> get_values() {
259 shared_ptr<values_copy> res_ref = ::seastar::make_shared<values_copy>();
260 auto& res = *(res_ref.get());
261 auto& mv = res.values;
262 res.metadata = get_local_impl()->metadata();
263 auto & functions = get_local_impl()->functions();
264 mv.reserve(functions.size());
265 for (auto&& i : functions) {
266 value_vector values;
267 values.reserve(i.size());
268 for (auto&& v : i) {
269 values.emplace_back(v());
270 }
271 mv.emplace_back(std::move(values));
272 }
273 return res_ref;
274}
275
276
277instance_id_type shard() {
278 if (engine_is_ready()) {
f67539c2 279 return to_sstring(this_shard_id());
11fdf7f2
TL
280 }
281
282 return sstring("0");
283}
284
285void impl::update_metrics_if_needed() {
286 if (_dirty) {
287 // Forcing the metadata to an empty initialization
288 // Will prevent using corrupted data if an exception is thrown
289 _metadata = ::seastar::make_shared<metric_metadata>();
290
291 auto mt_ref = ::seastar::make_shared<metric_metadata>();
292 auto &mt = *(mt_ref.get());
293 mt.reserve(_value_map.size());
294 _current_metrics.resize(_value_map.size());
295 size_t i = 0;
296 for (auto&& mf : _value_map) {
297 metric_metadata_vector metrics;
298 _current_metrics[i].clear();
299 for (auto&& m : mf.second) {
300 if (m.second && m.second->is_enabled()) {
301 metrics.emplace_back(m.second->info());
302 _current_metrics[i].emplace_back(m.second->get_function());
303 }
304 }
305 if (!metrics.empty()) {
306 // If nothing was added, no need to add the metric_family
307 // and no need to progress
308 mt.emplace_back(metric_family_metadata{mf.second.info(), std::move(metrics)});
309 i++;
310 }
311 }
312 // Maybe we didn't use all the original size
313 _current_metrics.resize(i);
314 _metadata = mt_ref;
315 _dirty = false;
316 }
317}
318
319shared_ptr<metric_metadata> impl::metadata() {
320 update_metrics_if_needed();
321 return _metadata;
322}
323
324std::vector<std::vector<metric_function>>& impl::functions() {
325 update_metrics_if_needed();
326 return _current_metrics;
327}
328
f67539c2 329void impl::add_registration(const metric_id& id, const metric_type& type, metric_function f, const description& d, bool enabled) {
11fdf7f2
TL
330 auto rm = ::seastar::make_shared<registered_metric>(id, f, enabled);
331 sstring name = id.full_name();
332 if (_value_map.find(name) != _value_map.end()) {
333 auto& metric = _value_map[name];
334 if (metric.find(id.labels()) != metric.end()) {
9f95a23c 335 throw double_registration("registering metrics twice for metrics: " + name);
11fdf7f2 336 }
f67539c2 337 if (metric.info().type != type.base_type) {
11fdf7f2
TL
338 throw std::runtime_error("registering metrics " + name + " registered with different type.");
339 }
340 metric[id.labels()] = rm;
341 } else {
f67539c2 342 _value_map[name].info().type = type.base_type;
11fdf7f2 343 _value_map[name].info().d = d;
f67539c2 344 _value_map[name].info().inherit_type = type.type_name;
11fdf7f2
TL
345 _value_map[name].info().name = id.full_name();
346 _value_map[name][id.labels()] = rm;
347 }
348 dirty();
349}
350
351}
352
353const bool metric_disabled = false;
354
355
356histogram& histogram::operator+=(const histogram& c) {
357 for (size_t i = 0; i < c.buckets.size(); i++) {
358 if (buckets.size() <= i) {
359 buckets.push_back(c.buckets[i]);
360 } else {
361 if (buckets[i].upper_bound != c.buckets[i].upper_bound) {
362 throw std::out_of_range("Trying to add histogram with different bucket limits");
363 }
364 buckets[i].count += c.buckets[i].count;
365 }
366 }
367 return *this;
368}
369
370histogram histogram::operator+(const histogram& c) const {
371 histogram res = *this;
372 res += c;
373 return res;
374}
375
376histogram histogram::operator+(histogram&& c) const {
377 c += *this;
378 return std::move(c);
379}
380
381}
382}