Kea 2.2.0
observation.cc
Go to the documentation of this file.
1// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <stats/observation.h>
11#include <cc/data.h>
12#include <chrono>
13#include <utility>
14
15using namespace std;
16using namespace std::chrono;
17using namespace isc::data;
18
19namespace isc {
20namespace stats {
21
22std::pair<bool, uint32_t>
23Observation::default_max_sample_count_ = std::make_pair(true, 20);
24
25std::pair<bool, StatsDuration>
26Observation::default_max_sample_age_ =
27 std::make_pair(false, StatsDuration::zero());
28
29Observation::Observation(const std::string& name, const int64_t value) :
30 name_(name), type_(STAT_INTEGER),
31 max_sample_count_(default_max_sample_count_),
32 max_sample_age_(default_max_sample_age_) {
33 setValue(value);
34}
35
36Observation::Observation(const std::string& name, const double value) :
37 name_(name), type_(STAT_FLOAT),
38 max_sample_count_(default_max_sample_count_),
39 max_sample_age_(default_max_sample_age_) {
40 setValue(value);
41}
42
43Observation::Observation(const std::string& name, const StatsDuration& value) :
44 name_(name), type_(STAT_DURATION),
45 max_sample_count_(default_max_sample_count_),
46 max_sample_age_(default_max_sample_age_) {
47 setValue(value);
48}
49
50Observation::Observation(const std::string& name, const std::string& value) :
51 name_(name), type_(STAT_STRING),
52 max_sample_count_(default_max_sample_count_),
53 max_sample_age_(default_max_sample_age_) {
54 setValue(value);
55}
56
58 switch(type_) {
59 case STAT_INTEGER: {
60 setMaxSampleAgeInternal(integer_samples_, duration, STAT_INTEGER);
61 return;
62 }
63 case STAT_FLOAT: {
64 setMaxSampleAgeInternal(float_samples_, duration, STAT_FLOAT);
65 return;
66 }
67 case STAT_DURATION: {
68 setMaxSampleAgeInternal(duration_samples_, duration, STAT_DURATION);
69 return;
70 }
71 case STAT_STRING: {
72 setMaxSampleAgeInternal(string_samples_, duration, STAT_STRING);
73 return;
74 }
75 default:
76 isc_throw(InvalidStatType, "Unknown statistic type: "
77 << typeToText(type_));
78 };
79}
80
81void Observation::setMaxSampleCount(uint32_t max_samples) {
82 switch(type_) {
83 case STAT_INTEGER: {
84 setMaxSampleCountInternal(integer_samples_, max_samples, STAT_INTEGER);
85 return;
86 }
87 case STAT_FLOAT: {
88 setMaxSampleCountInternal(float_samples_, max_samples, STAT_FLOAT);
89 return;
90 }
91 case STAT_DURATION: {
92 setMaxSampleCountInternal(duration_samples_, max_samples, STAT_DURATION);
93 return;
94 }
95 case STAT_STRING: {
96 setMaxSampleCountInternal(string_samples_, max_samples, STAT_STRING);
97 return;
98 }
99 default:
100 isc_throw(InvalidStatType, "Unknown statistic type: "
101 << typeToText(type_));
102 };
103}
104
105void Observation::addValue(const int64_t value) {
106 IntegerSample current = getInteger();
107 setValue(current.first + value);
108}
109
110void Observation::addValue(const double value) {
111 FloatSample current = getFloat();
112 setValue(current.first + value);
113}
114
116 DurationSample current = getDuration();
117 setValue(current.first + value);
118}
119
120void Observation::addValue(const std::string& value) {
121 StringSample current = getString();
122 setValue(current.first + value);
123}
124
125void Observation::setValue(const int64_t value) {
126 setValueInternal(value, integer_samples_, STAT_INTEGER);
127}
128
129void Observation::setValue(const double value) {
130 setValueInternal(value, float_samples_, STAT_FLOAT);
131}
132
134 setValueInternal(value, duration_samples_, STAT_DURATION);
135}
136
137void Observation::setValue(const std::string& value) {
138 setValueInternal(value, string_samples_, STAT_STRING);
139}
140
141size_t Observation::getSize() const {
142 size_t size = 0;
143 switch(type_) {
144 case STAT_INTEGER: {
145 size = getSizeInternal(integer_samples_, STAT_INTEGER);
146 return (size);
147 }
148 case STAT_FLOAT: {
149 size = getSizeInternal(float_samples_, STAT_FLOAT);
150 return (size);
151 }
152 case STAT_DURATION: {
153 size = getSizeInternal(duration_samples_, STAT_DURATION);
154 return (size);
155 }
156 case STAT_STRING: {
157 size = getSizeInternal(string_samples_, STAT_STRING);
158 return (size);
159 }
160 default:
161 isc_throw(InvalidStatType, "Unknown statistic type: "
162 << typeToText(type_));
163 };
164 return (size);
165}
166
167std::pair<bool, StatsDuration> Observation::getMaxSampleAge() const {
168 return (max_sample_age_);
169}
170
171std::pair<bool, uint32_t> Observation::getMaxSampleCount() const {
172 return (max_sample_count_);
173}
174
175template<typename StorageType>
176size_t Observation::getSizeInternal(StorageType& storage, Type exp_type) const {
177 if (type_ != exp_type) {
178 isc_throw(InvalidStatType, "Invalid statistic type requested: "
179 << typeToText(exp_type) << ", but the actual type is "
180 << typeToText(type_));
181 } else {
182 return (storage.size());
183 }
184 return (0); // to avoid compilation error
185}
186
187template<typename SampleType, typename StorageType>
188void Observation::setValueInternal(SampleType value, StorageType& storage,
189 Type exp_type) {
190 if (type_ != exp_type) {
191 isc_throw(InvalidStatType, "Invalid statistic type requested: "
192 << typeToText(exp_type) << ", but the actual type is "
193 << typeToText(type_));
194 }
195
196 if (storage.empty()) {
197 storage.push_back(make_pair(value, SampleClock::now()));
198 } else {
199 // Storing of more than one sample
200 storage.push_front(make_pair(value, SampleClock::now()));
201
202 if (max_sample_count_.first) {
203 // if max_sample_count_ is set to true
204 // and size of storage is equal to max_sample_count_
205 if (storage.size() > max_sample_count_.second) {
206 storage.pop_back(); // removing the last element
207 }
208 } else {
209 StatsDuration range_of_storage =
210 storage.front().second - storage.back().second;
211 // removing samples until the range_of_storage
212 // stops exceeding the duration limit
213 while (range_of_storage > max_sample_age_.second) {
214 storage.pop_back();
215 range_of_storage =
216 storage.front().second - storage.back().second;
217 }
218 }
219 }
220}
221
223 return (getValueInternal<IntegerSample>(integer_samples_, STAT_INTEGER));
224}
225
227 return (getValueInternal<FloatSample>(float_samples_, STAT_FLOAT));
228}
229
231 return (getValueInternal<DurationSample>(duration_samples_, STAT_DURATION));
232}
233
235 return (getValueInternal<StringSample>(string_samples_, STAT_STRING));
236}
237
238template<typename SampleType, typename Storage>
239SampleType Observation::getValueInternal(Storage& storage, Type exp_type) const {
240 if (type_ != exp_type) {
241 isc_throw(InvalidStatType, "Invalid statistic type requested: "
242 << typeToText(exp_type) << ", but the actual type is "
243 << typeToText(type_));
244 }
245
246 if (storage.empty()) {
247 // That should never happen. The first element is always initialized in
248 // the constructor. reset() sets its value to zero, but the element should
249 // still be there.
250 isc_throw(Unexpected, "Observation storage container empty");
251 }
252 return (*storage.begin());
253}
254
255std::list<IntegerSample> Observation::getIntegers() const {
256 return (getValuesInternal<IntegerSample>(integer_samples_, STAT_INTEGER));
257}
258
259std::list<FloatSample> Observation::getFloats() const {
260 return (getValuesInternal<FloatSample>(float_samples_, STAT_FLOAT));
261}
262
263std::list<DurationSample> Observation::getDurations() const {
264 return (getValuesInternal<DurationSample>(duration_samples_, STAT_DURATION));
265}
266
267std::list<StringSample> Observation::getStrings() const {
268 return (getValuesInternal<StringSample>(string_samples_, STAT_STRING));
269}
270
271template<typename SampleType, typename Storage>
272std::list<SampleType> Observation::getValuesInternal(Storage& storage,
273 Type exp_type) const {
274 if (type_ != exp_type) {
275 isc_throw(InvalidStatType, "Invalid statistic type requested: "
276 << typeToText(exp_type) << ", but the actual type is "
277 << typeToText(type_));
278 }
279
280 if (storage.empty()) {
281 // That should never happen. The first element is always initialized in
282 // the constructor. reset() sets its value to zero, but the element should
283 // still be there.
284 isc_throw(Unexpected, "Observation storage container empty");
285 }
286 return (storage);
287}
288
289template<typename StorageType>
290void Observation::setMaxSampleAgeInternal(StorageType& storage,
291 const StatsDuration& duration,
292 Type exp_type) {
293 if (type_ != exp_type) {
294 isc_throw(InvalidStatType, "Invalid statistic type requested: "
295 << typeToText(exp_type) << ", but the actual type is "
296 << typeToText(type_));
297 }
298 // setting new value of max_sample_age_
299 max_sample_age_.first = true;
300 max_sample_age_.second = duration;
301 // deactivating the max_sample_count_ limit
302 max_sample_count_.first = false;
303
304 StatsDuration range_of_storage =
305 storage.front().second - storage.back().second;
306
307 while (range_of_storage > duration) {
308 // deleting elements which are exceeding the duration limit
309 storage.pop_back();
310 range_of_storage = storage.front().second - storage.back().second;
311 }
312}
313
314template<typename StorageType>
315void Observation::setMaxSampleCountInternal(StorageType& storage,
316 uint32_t max_samples,
317 Type exp_type) {
318 if (type_ != exp_type) {
319 isc_throw(InvalidStatType, "Invalid statistic type requested: "
320 << typeToText(exp_type) << ", but the actual type is "
321 << typeToText(type_));
322 }
323 // Should we refuse the max_samples = 0 value here?
324 // setting new value of max_sample_count_
325 max_sample_count_.first = true;
326 max_sample_count_.second = max_samples;
327 // deactivating the max_sample_age_ limit
328 max_sample_age_.first = false;
329
330 while (storage.size() > max_samples) {
331 // deleting elements which are exceeding the max_samples limit
332 storage.pop_back();
333 }
334}
335
337 // setting new value of default_max_sample_age_
338 default_max_sample_age_.second = duration;
339}
340
341void Observation::setMaxSampleCountDefault(uint32_t max_samples) {
342 if (max_samples == 0) {
343 // deactivating the default_max_sample_count_ limit
344 default_max_sample_count_.first = false;
345 default_max_sample_age_.first = true;
346 } else {
347 // setting new value of default_max_sample_count_
348 default_max_sample_count_.second = max_samples;
349 // deactivating the default_max_sample_age_ limit
350 default_max_sample_age_.first = false;
351 default_max_sample_count_.first = true;
352 }
353}
354
356 return (default_max_sample_age_.second);
357}
358
360 if (default_max_sample_count_.first) {
361 return (default_max_sample_count_.second);
362 } else {
363 return (0);
364 }
365}
366
367std::string Observation::typeToText(Type type) {
368 std::stringstream tmp;
369 switch (type) {
370 case STAT_INTEGER:
371 tmp << "integer";
372 break;
373 case STAT_FLOAT:
374 tmp << "float";
375 break;
376 case STAT_DURATION:
377 tmp << "duration";
378 break;
379 case STAT_STRING:
380 tmp << "string";
381 break;
382 default:
383 tmp << "unknown";
384 break;
385 }
386 tmp << "(" << type << ")";
387 return (tmp.str());
388}
389
392
393 ElementPtr list = isc::data::Element::createList(); // multiple observations
394 ElementPtr entry;
395 ElementPtr value;
396 ElementPtr timestamp;
397
398 // Support for retrieving more than one sample
399 // retrieving all samples of indicated observation
400 switch (type_) {
401 case STAT_INTEGER: {
402 std::list<IntegerSample> s = getIntegers(); // List of all integer samples
403
404 // Iteration over all elements in the list
405 // and adding alternately value and timestamp to the entry
406 for (std::list<IntegerSample>::iterator it = s.begin(); it != s.end(); ++it) {
408 value = isc::data::Element::create(static_cast<int64_t>((*it).first));
409 timestamp = isc::data::Element::create(isc::util::clockToText((*it).second));
410
411 entry->add(value);
412 entry->add(timestamp);
413
414 list->add(entry);
415 }
416 break;
417 }
418 case STAT_FLOAT: {
419 std::list<FloatSample> s = getFloats();
420
421 // Iteration over all elements in the list
422 // and adding alternately value and timestamp to the entry
423 for (std::list<FloatSample>::iterator it = s.begin(); it != s.end(); ++it) {
425 value = isc::data::Element::create((*it).first);
426 timestamp = isc::data::Element::create(isc::util::clockToText((*it).second));
427
428 entry->add(value);
429 entry->add(timestamp);
430
431 list->add(entry);
432 }
433 break;
434 }
435 case STAT_DURATION: {
436 std::list<DurationSample> s = getDurations();
437
438 // Iteration over all elements in the list
439 // and adding alternately value and timestamp to the entry
440 for (std::list<DurationSample>::iterator it = s.begin(); it != s.end(); ++it) {
443 timestamp = isc::data::Element::create(isc::util::clockToText((*it).second));
444
445 entry->add(value);
446 entry->add(timestamp);
447
448 list->add(entry);
449 }
450 break;
451 }
452 case STAT_STRING: {
453 std::list<StringSample> s = getStrings();
454
455 // Iteration over all elements in the list
456 // and adding alternately value and timestamp to the entry
457 for (std::list<StringSample>::iterator it = s.begin(); it != s.end(); ++it) {
459 value = isc::data::Element::create((*it).first);
460 timestamp = isc::data::Element::create(isc::util::clockToText((*it).second));
461
462 entry->add(value);
463 entry->add(timestamp);
464
465 list->add(entry);
466 }
467 break;
468 }
469 default:
470 isc_throw(InvalidStatType, "Unknown statistic type: "
471 << typeToText(type_));
472 };
473
474 return (list);
475}
476
478 switch(type_) {
479 case STAT_INTEGER: {
480 integer_samples_.clear();
481 setValue(static_cast<int64_t>(0));
482 return;
483 }
484 case STAT_FLOAT: {
485 float_samples_.clear();
486 setValue(0.0);
487 return;
488 }
489 case STAT_DURATION: {
490 duration_samples_.clear();
491 setValue(StatsDuration::zero());
492 return;
493 }
494 case STAT_STRING: {
495 string_samples_.clear();
496 setValue(string(""));
497 return;
498 }
499 default:
500 isc_throw(InvalidStatType, "Unknown statistic type: "
501 << typeToText(type_));
502 };
503}
504
505} // end of namespace stats
506} // end of namespace isc
A generic exception that is thrown when an unexpected error condition occurs.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:241
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:286
Exception thrown if invalid statistic type is used.
Definition: observation.h:24
static std::string typeToText(Type type)
Converts statistic type to string.
Definition: observation.cc:367
static const StatsDuration & getMaxSampleAgeDefault()
Get default maximum age of samples.
Definition: observation.cc:355
void setValue(const int64_t value)
@
Definition: observation.cc:125
std::list< FloatSample > getFloats() const
Returns observed float samples.
Definition: observation.cc:259
void reset()
Resets statistic.
Definition: observation.cc:477
FloatSample getFloat() const
Returns observed float sample.
Definition: observation.cc:226
static uint32_t getMaxSampleCountDefault()
Get default maximum count of samples.
Definition: observation.cc:359
std::pair< bool, StatsDuration > getMaxSampleAge() const
Returns both values of max_sample_age_ of statistic.
Definition: observation.cc:167
void addValue(const int64_t value)
Records incremental integer observation.
Definition: observation.cc:105
StringSample getString() const
Returns observed string sample.
Definition: observation.cc:234
size_t getSize() const
Returns size of observed storage.
Definition: observation.cc:141
Type
Type of available statistics.
Definition: observation.h:95
@ STAT_INTEGER
this statistic is unsigned 64-bit integer value
Definition: observation.h:96
@ STAT_STRING
this statistic represents a string
Definition: observation.h:99
@ STAT_FLOAT
this statistic is a floating point value
Definition: observation.h:97
@ STAT_DURATION
this statistic represents time duration
Definition: observation.h:98
isc::data::ConstElementPtr getJSON() const
Returns as a JSON structure.
Definition: observation.cc:391
void setMaxSampleCount(uint32_t max_samples)
Determines how many samples of a given statistic should be kept.
Definition: observation.cc:81
static void setMaxSampleCountDefault(uint32_t max_samples)
Determines default maximum count of samples.
Definition: observation.cc:341
IntegerSample getInteger() const
Returns observed integer sample.
Definition: observation.cc:222
static void setMaxSampleAgeDefault(const StatsDuration &duration)
Determines default maximum age of samples.
Definition: observation.cc:336
void setMaxSampleAge(const StatsDuration &duration)
Determines maximum age of samples.
Definition: observation.cc:57
std::list< StringSample > getStrings() const
Returns observed string samples.
Definition: observation.cc:267
std::pair< bool, uint32_t > getMaxSampleCount() const
Returns both values of max_sample_count_ of statistic.
Definition: observation.cc:171
std::list< IntegerSample > getIntegers() const
Returns observed integer samples.
Definition: observation.cc:255
std::list< DurationSample > getDurations() const
Returns observed duration samples.
Definition: observation.cc:263
Observation(const std::string &name, const int64_t value)
Constructor for integer observations.
Definition: observation.cc:29
DurationSample getDuration() const
Returns observed duration sample.
Definition: observation.cc:230
const Name & name_
Definition: dns/message.cc:693
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
std::pair< double, SampleClock::time_point > FloatSample
Float (implemented as double precision)
Definition: observation.h:59
std::pair< int64_t, SampleClock::time_point > IntegerSample
Integer (implemented as signed 64-bit integer)
Definition: observation.h:56
std::pair< std::string, SampleClock::time_point > StringSample
String.
Definition: observation.h:65
std::pair< StatsDuration, SampleClock::time_point > DurationSample
Time Duration.
Definition: observation.h:62
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
std::chrono::system_clock::duration StatsDuration
Defines duration type.
Definition: observation.h:39
std::string durationToText(boost::posix_time::time_duration dur, size_t fsecs_precision=MAX_FSECS_PRECISION)
Converts StatsDuration to text.
std::string clockToText(std::chrono::system_clock::time_point t, size_t fsecs_precision)
Converts chrono time point structure to text.
Defines the logger used by the top-level component of kea-lfc.