]>
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) 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 | ||
30 | namespace seastar { | |
31 | namespace metrics { | |
32 | ||
9f95a23c TL |
33 | double_registration::double_registration(std::string what): std::runtime_error(what) {} |
34 | ||
11fdf7f2 TL |
35 | metric_groups::metric_groups() noexcept : _impl(impl::create_metric_groups()) { |
36 | } | |
37 | ||
38 | void metric_groups::clear() { | |
39 | _impl = impl::create_metric_groups(); | |
40 | } | |
41 | ||
42 | metric_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 | } | |
47 | metric_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 |
51 | metric_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 |
55 | metric_group::metric_group() noexcept = default; |
56 | metric_group::~metric_group() = default; | |
57 | metric_group::metric_group(const group_name_type& name, std::initializer_list<metric_definition> l) { | |
58 | add_group(name, l); | |
59 | } | |
60 | ||
61 | metric_group_definition::metric_group_definition(const group_name_type& name, std::initializer_list<metric_definition> l) : name(name), metrics(l) { | |
62 | } | |
63 | ||
64 | metric_group_definition::~metric_group_definition() = default; | |
65 | ||
66 | metric_groups::~metric_groups() = default; | |
67 | metric_definition::metric_definition(metric_definition&& m) noexcept : _impl(std::move(m._impl)) { | |
68 | } | |
69 | ||
70 | metric_definition::~metric_definition() = default; | |
71 | ||
72 | metric_definition::metric_definition(impl::metric_definition_impl const& m) noexcept : | |
73 | _impl(std::make_unique<impl::metric_definition_impl>(m)) { | |
74 | } | |
75 | ||
76 | bool 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 | ||
82 | bool 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 | ||
89 | static 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 | ||
97 | boost::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 | ||
107 | future<> 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 | ||
116 | bool label_instance::operator!=(const label_instance& id2) const { | |
117 | auto& id1 = *this; | |
118 | return !(id1 == id2); | |
119 | } | |
120 | ||
121 | label shard_label("shard"); | |
11fdf7f2 TL |
122 | namespace impl { |
123 | ||
124 | registered_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 | ||
130 | metric_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 | ||
143 | metric_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 | ||
159 | metric_definition_impl& metric_definition_impl::operator ()(bool _enabled) { | |
160 | enabled = _enabled; | |
161 | return *this; | |
162 | } | |
163 | ||
164 | metric_definition_impl& metric_definition_impl::operator ()(const label_instance& label) { | |
165 | labels[label.key()] = label.value(); | |
166 | return *this; | |
167 | } | |
168 | ||
f67539c2 TL |
169 | metric_definition_impl& metric_definition_impl::set_type(const sstring& type_name) { |
170 | type.type_name = type_name; | |
171 | return *this; | |
172 | } | |
173 | ||
11fdf7f2 TL |
174 | std::unique_ptr<metric_groups_def> create_metric_groups() { |
175 | return std::make_unique<metric_groups_impl>(); | |
176 | } | |
177 | ||
178 | metric_groups_impl::~metric_groups_impl() { | |
9f95a23c | 179 | for (const auto& i : _registration) { |
11fdf7f2 TL |
180 | unregister_metric(i); |
181 | } | |
182 | } | |
183 | ||
184 | metric_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 | ||
194 | metric_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 | ||
201 | metric_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 | ||
208 | bool metric_id::operator<( | |
209 | const metric_id& id2) const { | |
210 | return as_tuple() < id2.as_tuple(); | |
211 | } | |
212 | ||
213 | static 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 | ||
219 | sstring metric_id::full_name() const { | |
220 | return safe_name(_group + "_" + _name); | |
221 | } | |
222 | ||
223 | bool 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 | ||
231 | shared_ptr<impl> get_local_impl() { | |
232 | static thread_local auto the_impl = ::seastar::make_shared<impl>(); | |
233 | return the_impl; | |
234 | } | |
235 | void 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 | ||
250 | void unregister_metric(const metric_id & id) { | |
251 | get_local_impl()->remove_registration(id); | |
252 | } | |
253 | ||
254 | const value_map& get_value_map() { | |
255 | return get_local_impl()->get_value_map(); | |
256 | } | |
257 | ||
258 | foreign_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 | ||
277 | instance_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 | ||
285 | void 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 | ||
319 | shared_ptr<metric_metadata> impl::metadata() { | |
320 | update_metrics_if_needed(); | |
321 | return _metadata; | |
322 | } | |
323 | ||
324 | std::vector<std::vector<metric_function>>& impl::functions() { | |
325 | update_metrics_if_needed(); | |
326 | return _current_metrics; | |
327 | } | |
328 | ||
f67539c2 | 329 | void 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 | ||
353 | const bool metric_disabled = false; | |
354 | ||
355 | ||
356 | histogram& 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 | ||
370 | histogram histogram::operator+(const histogram& c) const { | |
371 | histogram res = *this; | |
372 | res += c; | |
373 | return res; | |
374 | } | |
375 | ||
376 | histogram histogram::operator+(histogram&& c) const { | |
377 | c += *this; | |
378 | return std::move(c); | |
379 | } | |
380 | ||
381 | } | |
382 | } |