Kea 2.7.5
observation.cc
Go to the documentation of this file.
1// Copyright (C) 2015-2024 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
13#include <chrono>
14#include <utility>
15
16using namespace std;
17using namespace std::chrono;
18using namespace isc::data;
19using namespace isc::util;
20
21namespace isc {
22namespace stats {
23
24std::pair<bool, uint32_t>
25Observation::default_max_sample_count_ = std::make_pair(true, 20);
26
27std::pair<bool, StatsDuration>
28Observation::default_max_sample_age_ =
29 std::make_pair(false, StatsDuration::zero());
30
31Observation::Observation(const std::string& name, const int64_t value) :
32 name_(name), type_(STAT_INTEGER),
33 max_sample_count_(default_max_sample_count_),
34 max_sample_age_(default_max_sample_age_) {
35 setValue(value);
36}
37
38Observation::Observation(const std::string& name, const int128_t& value) :
39 name_(name), type_(STAT_BIG_INTEGER),
40 max_sample_count_(default_max_sample_count_),
41 max_sample_age_(default_max_sample_age_) {
42 setValue(value);
43}
44
45Observation::Observation(const std::string& name, const double value) :
46 name_(name), type_(STAT_FLOAT),
47 max_sample_count_(default_max_sample_count_),
48 max_sample_age_(default_max_sample_age_) {
49 setValue(value);
50}
51
52Observation::Observation(const std::string& name, const StatsDuration& value) :
53 name_(name), type_(STAT_DURATION),
54 max_sample_count_(default_max_sample_count_),
55 max_sample_age_(default_max_sample_age_) {
56 setValue(value);
57}
58
59Observation::Observation(const std::string& name, const std::string& value) :
60 name_(name), type_(STAT_STRING),
61 max_sample_count_(default_max_sample_count_),
62 max_sample_age_(default_max_sample_age_) {
63 setValue(value);
64}
65
67 switch(type_) {
68 case STAT_INTEGER: {
69 setMaxSampleAgeInternal(integer_samples_, duration, STAT_INTEGER);
70 return;
71 }
72 case STAT_BIG_INTEGER: {
73 setMaxSampleAgeInternal(big_integer_samples_, duration, STAT_BIG_INTEGER);
74 return;
75 }
76 case STAT_FLOAT: {
77 setMaxSampleAgeInternal(float_samples_, duration, STAT_FLOAT);
78 return;
79 }
80 case STAT_DURATION: {
81 setMaxSampleAgeInternal(duration_samples_, duration, STAT_DURATION);
82 return;
83 }
84 case STAT_STRING: {
85 setMaxSampleAgeInternal(string_samples_, duration, STAT_STRING);
86 return;
87 }
88 default:
89 isc_throw(InvalidStatType, "Unknown statistic type: "
90 << typeToText(type_));
91 };
92}
93
94void Observation::setMaxSampleCount(uint32_t max_samples) {
95 switch(type_) {
96 case STAT_INTEGER: {
97 setMaxSampleCountInternal(integer_samples_, max_samples, STAT_INTEGER);
98 return;
99 }
100 case STAT_BIG_INTEGER: {
101 setMaxSampleCountInternal(big_integer_samples_, max_samples, STAT_BIG_INTEGER);
102 return;
103 }
104 case STAT_FLOAT: {
105 setMaxSampleCountInternal(float_samples_, max_samples, STAT_FLOAT);
106 return;
107 }
108 case STAT_DURATION: {
109 setMaxSampleCountInternal(duration_samples_, max_samples, STAT_DURATION);
110 return;
111 }
112 case STAT_STRING: {
113 setMaxSampleCountInternal(string_samples_, max_samples, STAT_STRING);
114 return;
115 }
116 default:
117 isc_throw(InvalidStatType, "Unknown statistic type: "
118 << typeToText(type_));
119 };
120}
121
122void Observation::addValue(const int64_t value) {
123 IntegerSample current = getInteger();
124 setValue(current.first + value);
125}
126
127void Observation::addValue(const int128_t& value) {
129 setValue(current.first + value);
130}
131
132void Observation::addValue(const double value) {
133 FloatSample current = getFloat();
134 setValue(current.first + value);
135}
136
138 DurationSample current = getDuration();
139 setValue(current.first + value);
140}
141
142void Observation::addValue(const std::string& value) {
143 StringSample current = getString();
144 setValue(current.first + value);
145}
146
147void Observation::setValue(const int64_t value) {
148 setValueInternal(value, integer_samples_, STAT_INTEGER);
149}
150
151void Observation::setValue(const int128_t& value) {
152 setValueInternal(value, big_integer_samples_, STAT_BIG_INTEGER);
153}
154
155void Observation::setValue(const double value) {
156 setValueInternal(value, float_samples_, STAT_FLOAT);
157}
158
160 setValueInternal(value, duration_samples_, STAT_DURATION);
161}
162
163void Observation::setValue(const std::string& value) {
164 setValueInternal(value, string_samples_, STAT_STRING);
165}
166
167size_t Observation::getSize() const {
168 size_t size = 0;
169 switch(type_) {
170 case STAT_INTEGER: {
171 size = getSizeInternal(integer_samples_, STAT_INTEGER);
172 return (size);
173 }
174 case STAT_BIG_INTEGER: {
175 size = getSizeInternal(big_integer_samples_, STAT_BIG_INTEGER);
176 return (size);
177 }
178 case STAT_FLOAT: {
179 size = getSizeInternal(float_samples_, STAT_FLOAT);
180 return (size);
181 }
182 case STAT_DURATION: {
183 size = getSizeInternal(duration_samples_, STAT_DURATION);
184 return (size);
185 }
186 case STAT_STRING: {
187 size = getSizeInternal(string_samples_, STAT_STRING);
188 return (size);
189 }
190 default:
191 isc_throw(InvalidStatType, "Unknown statistic type: "
192 << typeToText(type_));
193 };
194 return (size);
195}
196
197std::pair<bool, StatsDuration> Observation::getMaxSampleAge() const {
198 return (max_sample_age_);
199}
200
201std::pair<bool, uint32_t> Observation::getMaxSampleCount() const {
202 return (max_sample_count_);
203}
204
205template<typename StorageType>
206size_t Observation::getSizeInternal(StorageType& storage, Type exp_type) const {
207 if (type_ != exp_type) {
208 isc_throw(InvalidStatType, "Invalid statistic type requested: "
209 << typeToText(exp_type) << ", but the actual type is "
210 << typeToText(type_));
211 } else {
212 return (storage.size());
213 }
214 return (0); // to avoid compilation error
215}
216
217template<typename SampleType, typename StorageType>
218void Observation::setValueInternal(SampleType value, StorageType& storage,
219 Type exp_type) {
220 if (type_ != exp_type) {
221 isc_throw(InvalidStatType, "Invalid statistic type requested: "
222 << typeToText(exp_type) << ", but the actual type is "
223 << typeToText(type_));
224 }
225
226 if (storage.empty()) {
227 storage.push_back(make_pair(value, SampleClock::now()));
228 } else {
229 // Storing of more than one sample
230 storage.push_front(make_pair(value, SampleClock::now()));
231
232 if (max_sample_count_.first) {
233 // if max_sample_count_ is set to true
234 // and size of storage is equal to max_sample_count_
235 if (storage.size() > max_sample_count_.second) {
236 storage.pop_back(); // removing the last element
237 }
238 } else {
239 StatsDuration range_of_storage =
240 storage.front().second - storage.back().second;
241 // removing samples until the range_of_storage
242 // stops exceeding the duration limit
243 while (range_of_storage > max_sample_age_.second) {
244 storage.pop_back();
245 range_of_storage =
246 storage.front().second - storage.back().second;
247 }
248 }
249 }
250}
251
253 return (getValueInternal<IntegerSample>(integer_samples_, STAT_INTEGER));
254}
255
257 return (getValueInternal<BigIntegerSample>(big_integer_samples_, STAT_BIG_INTEGER));
258}
259
261 return (getValueInternal<FloatSample>(float_samples_, STAT_FLOAT));
262}
263
265 return (getValueInternal<DurationSample>(duration_samples_, STAT_DURATION));
266}
267
269 return (getValueInternal<StringSample>(string_samples_, STAT_STRING));
270}
271
272template<typename SampleType, typename Storage>
273SampleType Observation::getValueInternal(Storage& storage, 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.begin());
287}
288
289std::list<IntegerSample> Observation::getIntegers() const {
290 return (getValuesInternal<IntegerSample>(integer_samples_, STAT_INTEGER));
291}
292
293std::list<BigIntegerSample> Observation::getBigIntegers() const {
294 return (getValuesInternal<BigIntegerSample>(big_integer_samples_, STAT_BIG_INTEGER));
295}
296
297std::list<FloatSample> Observation::getFloats() const {
298 return (getValuesInternal<FloatSample>(float_samples_, STAT_FLOAT));
299}
300
301std::list<DurationSample> Observation::getDurations() const {
302 return (getValuesInternal<DurationSample>(duration_samples_, STAT_DURATION));
303}
304
305std::list<StringSample> Observation::getStrings() const {
306 return (getValuesInternal<StringSample>(string_samples_, STAT_STRING));
307}
308
309template<typename SampleType, typename Storage>
310std::list<SampleType> Observation::getValuesInternal(Storage& storage,
311 Type exp_type) const {
312 if (type_ != exp_type) {
313 isc_throw(InvalidStatType, "Invalid statistic type requested: "
314 << typeToText(exp_type) << ", but the actual type is "
315 << typeToText(type_));
316 }
317
318 if (storage.empty()) {
319 // That should never happen. The first element is always initialized in
320 // the constructor. reset() sets its value to zero, but the element should
321 // still be there.
322 isc_throw(Unexpected, "Observation storage container empty");
323 }
324 return (storage);
325}
326
327template<typename StorageType>
328void Observation::setMaxSampleAgeInternal(StorageType& storage,
329 const StatsDuration& duration,
330 Type exp_type) {
331 if (type_ != exp_type) {
332 isc_throw(InvalidStatType, "Invalid statistic type requested: "
333 << typeToText(exp_type) << ", but the actual type is "
334 << typeToText(type_));
335 }
336 // setting new value of max_sample_age_
337 max_sample_age_.first = true;
338 max_sample_age_.second = duration;
339 // deactivating the max_sample_count_ limit
340 max_sample_count_.first = false;
341
342 StatsDuration range_of_storage =
343 storage.front().second - storage.back().second;
344
345 while (range_of_storage > duration) {
346 // deleting elements which are exceeding the duration limit
347 storage.pop_back();
348 range_of_storage = storage.front().second - storage.back().second;
349 }
350}
351
352template<typename StorageType>
353void Observation::setMaxSampleCountInternal(StorageType& storage,
354 uint32_t max_samples,
355 Type exp_type) {
356 if (type_ != exp_type) {
357 isc_throw(InvalidStatType, "Invalid statistic type requested: "
358 << typeToText(exp_type) << ", but the actual type is "
359 << typeToText(type_));
360 }
361 // Should we refuse the max_samples = 0 value here?
362 // setting new value of max_sample_count_
363 max_sample_count_.first = true;
364 max_sample_count_.second = max_samples;
365 // deactivating the max_sample_age_ limit
366 max_sample_age_.first = false;
367
368 while (storage.size() > max_samples) {
369 // deleting elements which are exceeding the max_samples limit
370 storage.pop_back();
371 }
372}
373
375 // setting new value of default_max_sample_age_
376 default_max_sample_age_.second = duration;
377}
378
379void Observation::setMaxSampleCountDefault(uint32_t max_samples) {
380 if (max_samples == 0) {
381 // deactivating the default_max_sample_count_ limit
382 default_max_sample_count_.first = false;
383 default_max_sample_age_.first = true;
384 } else {
385 // setting new value of default_max_sample_count_
386 default_max_sample_count_.second = max_samples;
387 // deactivating the default_max_sample_age_ limit
388 default_max_sample_age_.first = false;
389 default_max_sample_count_.first = true;
390 }
391}
392
394 return (default_max_sample_age_.second);
395}
396
398 if (default_max_sample_count_.first) {
399 return (default_max_sample_count_.second);
400 } else {
401 return (0);
402 }
403}
404
405std::string Observation::typeToText(Type type) {
406 std::stringstream tmp;
407 switch (type) {
408 case STAT_INTEGER:
409 tmp << "integer";
410 break;
411 case STAT_BIG_INTEGER:
412 tmp << "big integer";
413 break;
414 case STAT_FLOAT:
415 tmp << "float";
416 break;
417 case STAT_DURATION:
418 tmp << "duration";
419 break;
420 case STAT_STRING:
421 tmp << "string";
422 break;
423 default:
424 tmp << "unknown";
425 break;
426 }
427 tmp << "(" << type << ")";
428 return (tmp.str());
429}
430
433 ElementPtr list = isc::data::Element::createList(); // multiple observations
434 ElementPtr entry;
435 ElementPtr value;
436 ElementPtr timestamp;
437
438 // Support for retrieving more than one sample
439 // retrieving all samples of indicated observation
440 switch (type_) {
441 case STAT_INTEGER: {
442 std::list<IntegerSample> s = getIntegers(); // List of all integer samples
443
444 // Iteration over all elements in the list
445 // and adding alternately value and timestamp to the entry
446 for (auto const& it : s) {
448 value = isc::data::Element::create(static_cast<int64_t>(it.first));
450
451 entry->add(value);
452 entry->add(timestamp);
453
454 list->add(entry);
455 }
456 break;
457 }
458 case STAT_BIG_INTEGER: {
459 std::list<BigIntegerSample> const& samples(getBigIntegers());
460
461 // Iterate over all elements in the list and alternately add
462 // value and timestamp to the entry.
463 for (BigIntegerSample const& i : samples) {
465 value = isc::data::Element::create(i.first);
467
468 entry->add(value);
469 entry->add(timestamp);
470
471 list->add(entry);
472 }
473 break;
474 }
475 case STAT_FLOAT: {
476 std::list<FloatSample> s = getFloats();
477
478 // Iteration over all elements in the list
479 // and adding alternately value and timestamp to the entry
480 for (auto const& it : s) {
482 value = isc::data::Element::create(it.first);
484
485 entry->add(value);
486 entry->add(timestamp);
487
488 list->add(entry);
489 }
490 break;
491 }
492 case STAT_DURATION: {
493 std::list<DurationSample> s = getDurations();
494
495 // Iteration over all elements in the list
496 // and adding alternately value and timestamp to the entry
497 for (auto const& it : s) {
501
502 entry->add(value);
503 entry->add(timestamp);
504
505 list->add(entry);
506 }
507 break;
508 }
509 case STAT_STRING: {
510 std::list<StringSample> s = getStrings();
511
512 // Iteration over all elements in the list
513 // and adding alternately value and timestamp to the entry
514 for (auto const& it : s) {
516 value = isc::data::Element::create(it.first);
518
519 entry->add(value);
520 entry->add(timestamp);
521
522 list->add(entry);
523 }
524 break;
525 }
526 default:
527 isc_throw(InvalidStatType, "Unknown statistic type: "
528 << typeToText(type_));
529 };
530
531 return (list);
532}
533
535 switch(type_) {
536 case STAT_INTEGER: {
537 integer_samples_.clear();
538 setValue(static_cast<int64_t>(0));
539 return;
540 }
541 case STAT_BIG_INTEGER: {
542 big_integer_samples_.clear();
543 setValue(int128_t(0));
544 return;
545 }
546 case STAT_FLOAT: {
547 float_samples_.clear();
548 setValue(0.0);
549 return;
550 }
551 case STAT_DURATION: {
552 duration_samples_.clear();
553 setValue(StatsDuration::zero());
554 return;
555 }
556 case STAT_STRING: {
557 string_samples_.clear();
558 setValue(string(""));
559 return;
560 }
561 default:
562 isc_throw(InvalidStatType, "Unknown statistic type: "
563 << typeToText(type_));
564 };
565}
566
567} // end of namespace stats
568} // 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:249
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
Exception thrown if invalid statistic type is used.
Definition observation.h:28
static std::string typeToText(Type type)
Converts statistic type to string.
static const StatsDuration & getMaxSampleAgeDefault()
Get default maximum age of samples.
void setValue(const int64_t value)
@
std::list< FloatSample > getFloats() const
Returns observed float samples.
void reset()
Resets statistic.
FloatSample getFloat() const
Returns observed float sample.
static uint32_t getMaxSampleCountDefault()
Get default maximum count of samples.
std::pair< bool, StatsDuration > getMaxSampleAge() const
Returns both values of max_sample_age_ of statistic.
void addValue(const int64_t value)
Records incremental integer observation.
StringSample getString() const
Returns observed string sample.
std::list< BigIntegerSample > getBigIntegers() const
Returns observed big-integer samples.
size_t getSize() const
Returns size of observed storage.
Type
Type of available statistics.
@ STAT_BIG_INTEGER
this statistic is signed 128-bit integer value
@ STAT_INTEGER
this statistic is signed 64-bit integer value
@ STAT_STRING
this statistic represents a string
@ STAT_FLOAT
this statistic is a floating point value
@ STAT_DURATION
this statistic represents time duration
isc::data::ConstElementPtr getJSON() const
Returns as a JSON structure.
void setMaxSampleCount(uint32_t max_samples)
Determines how many samples of a given statistic should be kept.
static void setMaxSampleCountDefault(uint32_t max_samples)
Determines default maximum count of samples.
IntegerSample getInteger() const
Returns observed integer sample.
static void setMaxSampleAgeDefault(const StatsDuration &duration)
Determines default maximum age of samples.
void setMaxSampleAge(const StatsDuration &duration)
Determines maximum age of samples.
BigIntegerSample getBigInteger() const
Returns observed integer sample.
std::list< StringSample > getStrings() const
Returns observed string samples.
std::pair< bool, uint32_t > getMaxSampleCount() const
Returns both values of max_sample_count_ of statistic.
std::list< IntegerSample > getIntegers() const
Returns observed integer samples.
std::list< DurationSample > getDurations() const
Returns observed duration samples.
Observation(const std::string &name, const int64_t value)
Constructor for integer observations.
DurationSample getDuration() const
Returns observed duration sample.
const Name & name_
#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:66
std::pair< int64_t, SampleClock::time_point > IntegerSample
Integer (implemented as signed 64-bit integer)
Definition observation.h:60
std::pair< std::string, SampleClock::time_point > StringSample
String.
Definition observation.h:72
std::pair< isc::util::int128_t, SampleClock::time_point > BigIntegerSample
BigInteger (implemented as signed 128-bit integer)
Definition observation.h:63
std::pair< StatsDuration, SampleClock::time_point > DurationSample
Time Duration.
Definition observation.h:69
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
std::chrono::system_clock::duration StatsDuration
Defines duration type.
Definition observation.h:43
boost::multiprecision::checked_int128_t int128_t
Definition bigints.h:19
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.