Coverage Report

Created: 2025-11-16 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kea/src/lib/stats/stats_mgr.cc
Line
Count
Source
1
// Copyright (C) 2015-2025 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 <exceptions/exceptions.h>
10
#include <stats/stats_mgr.h>
11
#include <cc/data.h>
12
#include <cc/command_interpreter.h>
13
#include <util/multi_threading_mgr.h>
14
#include <util/bigints.h>
15
16
#include <boost/make_shared.hpp>
17
18
#include <chrono>
19
20
using namespace std;
21
using namespace std::chrono;
22
using namespace isc::data;
23
using namespace isc::config;
24
using namespace isc::util;
25
26
namespace isc {
27
namespace stats {
28
29
StatsMgr&
30
140k
StatsMgr::instance() {
31
140k
    static StatsMgr stats_mgr;
32
140k
    return (stats_mgr);
33
140k
}
34
35
StatsMgr::StatsMgr() :
36
21
    global_(boost::make_shared<StatContext>()), mutex_(new mutex()) {
37
21
}
38
39
void
40
1.11M
StatsMgr::setValue(const string& name, const int64_t value) {
41
1.11M
    MultiThreadingLock lock(*mutex_);
42
1.11M
    setValueInternal(name, value);
43
1.11M
}
44
45
void
46
636
StatsMgr::setValue(const string& name, const int128_t& value) {
47
636
    MultiThreadingLock lock(*mutex_);
48
636
    setValueInternal(name, value);
49
636
}
50
51
void
52
0
StatsMgr::setValue(const string& name, const double value) {
53
0
    MultiThreadingLock lock(*mutex_);
54
0
    setValueInternal(name, value);
55
0
}
56
57
void
58
0
StatsMgr::setValue(const string& name, const StatsDuration& value) {
59
0
    MultiThreadingLock lock(*mutex_);
60
0
    setValueInternal(name, value);
61
0
}
62
63
void
64
0
StatsMgr::setValue(const string& name, const string& value) {
65
0
    MultiThreadingLock lock(*mutex_);
66
0
    setValueInternal(name, value);
67
0
}
68
69
void
70
62.9k
StatsMgr::addValue(const string& name, const int64_t value) {
71
62.9k
    MultiThreadingLock lock(*mutex_);
72
62.9k
    addValueInternal(name, value);
73
62.9k
}
74
75
void
76
0
StatsMgr::addValue(const string& name, const int128_t& value) {
77
0
    MultiThreadingLock lock(*mutex_);
78
0
    addValueInternal(name, value);
79
0
}
80
81
void
82
0
StatsMgr::addValue(const string& name, const double value) {
83
0
    MultiThreadingLock lock(*mutex_);
84
0
    addValueInternal(name, value);
85
0
}
86
87
void
88
0
StatsMgr::addValue(const string& name, const StatsDuration& value) {
89
0
    MultiThreadingLock lock(*mutex_);
90
0
    addValueInternal(name, value);
91
0
}
92
93
void
94
0
StatsMgr::addValue(const string& name, const string& value) {
95
0
    MultiThreadingLock lock(*mutex_);
96
0
    addValueInternal(name, value);
97
0
}
98
99
ObservationPtr
100
95.7k
StatsMgr::getObservation(const string& name) const {
101
95.7k
    MultiThreadingLock lock(*mutex_);
102
95.7k
    return (getObservationInternal(name));
103
95.7k
}
104
105
ObservationPtr
106
1.27M
StatsMgr::getObservationInternal(const string& name) const {
107
    /// @todo: Implement contexts.
108
    // Currently we keep everything in a global context.
109
1.27M
    return (global_->get(name));
110
1.27M
}
111
112
void
113
0
StatsMgr::addObservation(const ObservationPtr& stat) {
114
0
    MultiThreadingLock lock(*mutex_);
115
0
    addObservationInternal(stat);
116
0
}
117
118
void
119
82.9k
StatsMgr::addObservationInternal(const ObservationPtr& stat) {
120
    /// @todo: Implement contexts.
121
    // Currently we keep everything in a global context.
122
82.9k
    global_->add(stat);
123
82.9k
}
124
125
bool
126
0
StatsMgr::deleteObservation(const string& name) {
127
0
    MultiThreadingLock lock(*mutex_);
128
0
    return (deleteObservationInternal(name));
129
0
}
130
131
bool
132
0
StatsMgr::deleteObservationInternal(const string& name) {
133
    /// @todo: Implement contexts.
134
    // Currently we keep everything in a global context.
135
0
    return (global_->del(name));
136
0
}
137
138
bool
139
0
StatsMgr::setMaxSampleAge(const string& name, const StatsDuration& duration) {
140
0
    MultiThreadingLock lock(*mutex_);
141
0
    return (setMaxSampleAgeInternal(name, duration));
142
0
}
143
144
bool
145
StatsMgr::setMaxSampleAgeInternal(const string& name,
146
0
                                  const StatsDuration& duration) {
147
0
    ObservationPtr obs = getObservationInternal(name);
148
0
    if (obs) {
149
0
        obs->setMaxSampleAge(duration);
150
0
        return (true);
151
0
    }
152
0
    return (false);
153
0
}
154
155
bool
156
0
StatsMgr::setMaxSampleCount(const string& name, uint32_t max_samples) {
157
0
    MultiThreadingLock lock(*mutex_);
158
0
    return (setMaxSampleCountInternal(name, max_samples));
159
0
}
160
161
bool
162
StatsMgr::setMaxSampleCountInternal(const string& name,
163
0
                                    uint32_t max_samples) {
164
0
    ObservationPtr obs = getObservationInternal(name);
165
0
    if (obs) {
166
0
        obs->setMaxSampleCount(max_samples);
167
0
        return (true);
168
0
    }
169
0
    return (false);
170
0
}
171
172
void
173
0
StatsMgr::setMaxSampleAgeAll(const StatsDuration& duration) {
174
0
    MultiThreadingLock lock(*mutex_);
175
0
    setMaxSampleAgeAllInternal(duration);
176
0
}
177
178
void
179
0
StatsMgr::setMaxSampleAgeAllInternal(const StatsDuration& duration) {
180
0
    global_->setMaxSampleAgeAll(duration);
181
0
}
182
183
void
184
18.0k
StatsMgr::setMaxSampleCountAll(uint32_t max_samples) {
185
18.0k
    MultiThreadingLock lock(*mutex_);
186
18.0k
    setMaxSampleCountAllInternal(max_samples);
187
18.0k
}
188
189
void
190
18.0k
StatsMgr::setMaxSampleCountAllInternal(uint32_t max_samples) {
191
18.0k
    global_->setMaxSampleCountAll(max_samples);
192
18.0k
}
193
194
void
195
18.0k
StatsMgr::setMaxSampleAgeDefault(const StatsDuration& duration) {
196
18.0k
    MultiThreadingLock lock(*mutex_);
197
18.0k
    setMaxSampleAgeDefaultInternal(duration);
198
18.0k
}
199
200
void
201
18.0k
StatsMgr::setMaxSampleAgeDefaultInternal(const StatsDuration& duration) {
202
18.0k
    Observation::setMaxSampleAgeDefault(duration);
203
18.0k
}
204
205
void
206
18.0k
StatsMgr::setMaxSampleCountDefault(uint32_t max_samples) {
207
18.0k
    MultiThreadingLock lock(*mutex_);
208
18.0k
    setMaxSampleCountDefaultInternal(max_samples);
209
18.0k
}
210
211
void
212
18.0k
StatsMgr::setMaxSampleCountDefaultInternal(uint32_t max_samples) {
213
18.0k
    Observation::setMaxSampleCountDefault(max_samples);
214
18.0k
}
215
216
const StatsDuration&
217
0
StatsMgr::getMaxSampleAgeDefault() const {
218
0
    MultiThreadingLock lock(*mutex_);
219
0
    return (getMaxSampleAgeDefaultInternal());
220
0
}
221
222
const StatsDuration&
223
0
StatsMgr::getMaxSampleAgeDefaultInternal() const {
224
0
    return (Observation::getMaxSampleAgeDefault());
225
0
}
226
227
uint32_t
228
0
StatsMgr::getMaxSampleCountDefault() const {
229
0
    MultiThreadingLock lock(*mutex_);
230
0
    return (getMaxSampleCountDefaultInternal());
231
0
}
232
233
uint32_t
234
0
StatsMgr::getMaxSampleCountDefaultInternal() const {
235
0
    return (Observation::getMaxSampleCountDefault());
236
0
}
237
238
bool
239
0
StatsMgr::reset(const string& name) {
240
0
    MultiThreadingLock lock(*mutex_);
241
0
    return (resetInternal(name));
242
0
}
243
244
bool
245
0
StatsMgr::resetInternal(const string& name) {
246
0
    ObservationPtr obs = getObservationInternal(name);
247
0
    if (obs) {
248
0
        obs->reset();
249
0
        return (true);
250
0
    }
251
0
    return (false);
252
0
}
253
254
bool
255
82.1k
StatsMgr::del(const string& name) {
256
82.1k
    MultiThreadingLock lock(*mutex_);
257
82.1k
    return (delInternal(name));
258
82.1k
}
259
260
bool
261
82.1k
StatsMgr::delInternal(const string& name) {
262
82.1k
    return (global_->del(name));
263
82.1k
}
264
265
void
266
0
StatsMgr::removeAll() {
267
0
    MultiThreadingLock lock(*mutex_);
268
0
    removeAllInternal();
269
0
}
270
271
void
272
0
StatsMgr::removeAllInternal() {
273
0
    global_->clear();
274
0
}
275
276
ConstElementPtr
277
0
StatsMgr::get(const string& name) const {
278
0
    MultiThreadingLock lock(*mutex_);
279
0
    return (getInternal(name));
280
0
}
281
282
ConstElementPtr
283
0
StatsMgr::getInternal(const string& name) const {
284
0
    ElementPtr map = Element::createMap(); // a map
285
0
    ObservationPtr obs = getObservationInternal(name);
286
0
    if (obs) {
287
0
        map->set(name, obs->getJSON()); // that contains observations
288
0
    }
289
0
    return (map);
290
0
}
291
292
ConstElementPtr
293
0
StatsMgr::getAll() const {
294
0
    MultiThreadingLock lock(*mutex_);
295
0
    return (getAllInternal());
296
0
}
297
298
ConstElementPtr
299
0
StatsMgr::getAllGlobal() const {
300
0
    MultiThreadingLock lock(*mutex_);
301
0
    return (getAllGlobalInternal());
302
0
}
303
304
ConstElementPtr
305
0
StatsMgr::getAllInternal() const {
306
0
    return (global_->getAll());
307
0
}
308
309
ConstElementPtr
310
0
StatsMgr::getAllGlobalInternal() const {
311
0
    return (global_->getAllGlobal());
312
0
}
313
314
void
315
0
StatsMgr::resetAll() {
316
0
    MultiThreadingLock lock(*mutex_);
317
0
    resetAllInternal();
318
0
}
319
320
void
321
0
StatsMgr::resetAllInternal() {
322
0
    global_->resetAll();
323
0
}
324
325
size_t
326
0
StatsMgr::getSize(const string& name) const {
327
0
    MultiThreadingLock lock(*mutex_);
328
0
    return (getSizeInternal(name));
329
0
}
330
331
size_t
332
0
StatsMgr::getSizeInternal(const string& name) const {
333
0
    ObservationPtr obs = getObservationInternal(name);
334
0
    if (obs) {
335
0
        return (obs->getSize());
336
0
    }
337
0
    return (0);
338
0
}
339
340
size_t
341
0
StatsMgr::count() const {
342
0
    MultiThreadingLock lock(*mutex_);
343
0
    return (countInternal());
344
0
}
345
346
size_t
347
0
StatsMgr::countInternal() const {
348
0
    return (global_->size());
349
0
}
350
351
ConstElementPtr
352
StatsMgr::statisticSetMaxSampleAgeHandler(const string& /*name*/,
353
0
                                          const ConstElementPtr& params) {
354
0
    string name, error;
355
0
    StatsDuration duration;
356
0
    if (!StatsMgr::getStatName(params, name, error)) {
357
0
        return (createAnswer(CONTROL_RESULT_ERROR, error));
358
0
    }
359
0
    if (!StatsMgr::getStatDuration(params, duration, error)) {
360
0
        return (createAnswer(CONTROL_RESULT_ERROR, error));
361
0
    }
362
0
    if (StatsMgr::instance().setMaxSampleAge(name, duration)) {
363
0
        return (createAnswer(CONTROL_RESULT_SUCCESS,
364
0
                            "Statistic '" + name + "' duration limit is set."));
365
0
    } else {
366
0
        return (createAnswer(CONTROL_RESULT_ERROR,
367
0
                             "No '" + name + "' statistic found"));
368
0
    }
369
0
}
370
371
ConstElementPtr
372
StatsMgr::statisticSetMaxSampleCountHandler(const string& /*name*/,
373
0
                                            const ConstElementPtr& params) {
374
0
    string name, error;
375
0
    uint32_t max_samples;
376
0
    if (!StatsMgr::getStatName(params, name, error)) {
377
0
        return (createAnswer(CONTROL_RESULT_ERROR, error));
378
0
    }
379
0
    if (!StatsMgr::getStatMaxSamples(params, max_samples, error)) {
380
0
        return (createAnswer(CONTROL_RESULT_ERROR, error));
381
0
    }
382
0
    if (StatsMgr::instance().setMaxSampleCount(name, max_samples)) {
383
0
        return (createAnswer(CONTROL_RESULT_SUCCESS,
384
0
                            "Statistic '" + name + "' count limit is set."));
385
0
    } else {
386
0
        return (createAnswer(CONTROL_RESULT_ERROR,
387
0
                           "No '" + name + "' statistic found"));
388
0
    }
389
0
}
390
391
ConstElementPtr
392
StatsMgr::statisticGetHandler(const string& /*name*/,
393
0
                              const ConstElementPtr& params) {
394
0
    string name, error;
395
0
    if (!StatsMgr::getStatName(params, name, error)) {
396
0
        return (createAnswer(CONTROL_RESULT_ERROR, error));
397
0
    }
398
0
    return (createAnswer(CONTROL_RESULT_SUCCESS,
399
0
                         StatsMgr::instance().get(name)));
400
0
}
401
402
ConstElementPtr
403
StatsMgr::statisticResetHandler(const string& /*name*/,
404
1
                                const ConstElementPtr& params) {
405
1
    string name, error;
406
1
    if (!StatsMgr::getStatName(params, name, error)) {
407
1
        return (createAnswer(CONTROL_RESULT_ERROR, error));
408
1
    }
409
0
    if (StatsMgr::instance().reset(name)) {
410
0
        return (createAnswer(CONTROL_RESULT_SUCCESS,
411
0
                             "Statistic '" + name + "' reset."));
412
0
    } else {
413
0
        return (createAnswer(CONTROL_RESULT_ERROR,
414
0
                             "No '" + name + "' statistic found"));
415
0
    }
416
0
}
417
418
ConstElementPtr
419
StatsMgr::statisticRemoveHandler(const string& /*name*/,
420
0
                                 const ConstElementPtr& params) {
421
0
    string name, error;
422
0
    if (!StatsMgr::getStatName(params, name, error)) {
423
0
        return (createAnswer(CONTROL_RESULT_ERROR, error));
424
0
    }
425
0
    if (StatsMgr::instance().del(name)) {
426
0
        return (createAnswer(CONTROL_RESULT_SUCCESS,
427
0
                             "Statistic '" + name + "' removed."));
428
0
    } else {
429
0
        return (createAnswer(CONTROL_RESULT_ERROR,
430
0
                             "No '" + name + "' statistic found"));
431
0
    }
432
433
0
}
434
435
ConstElementPtr
436
StatsMgr::statisticRemoveAllHandler(const string& /*name*/,
437
0
                                    const ConstElementPtr& /*params*/) {
438
0
    StatsMgr::instance().removeAll();
439
0
    return (createAnswer(CONTROL_RESULT_SUCCESS,
440
0
                         "Warning: statistic-remove-all command is deprecated."
441
0
                         " All statistics removed."));
442
0
}
443
444
ConstElementPtr
445
StatsMgr::statisticGetAllHandler(const string& /*name*/,
446
0
                                 const ConstElementPtr& /*params*/) {
447
0
    ConstElementPtr all_stats = StatsMgr::instance().getAll();
448
0
    return (createAnswer(CONTROL_RESULT_SUCCESS, all_stats));
449
0
}
450
451
ConstElementPtr
452
StatsMgr::statisticGlobalGetAllHandler(const string& /*name*/,
453
0
                                       const ConstElementPtr& /*params*/) {
454
0
    ConstElementPtr all_stats = StatsMgr::instance().getAllGlobal();
455
0
    return (createAnswer(CONTROL_RESULT_SUCCESS, all_stats));
456
0
}
457
458
ConstElementPtr
459
StatsMgr::statisticResetAllHandler(const string& /*name*/,
460
0
                                   const ConstElementPtr& /*params*/) {
461
0
    StatsMgr::instance().resetAll();
462
0
    return (createAnswer(CONTROL_RESULT_SUCCESS,
463
0
                         "All statistics reset to neutral values."));
464
0
}
465
466
ConstElementPtr
467
0
StatsMgr::statisticSetMaxSampleAgeAllHandler(const ConstElementPtr& params) {
468
0
    string error;
469
0
    StatsDuration duration;
470
0
    if (!StatsMgr::getStatDuration(params, duration, error)) {
471
0
        return (createAnswer(CONTROL_RESULT_ERROR, error));
472
0
    }
473
0
    MultiThreadingLock lock(*mutex_);
474
0
    StatsMgr::instance().setMaxSampleCountDefaultInternal(0);
475
0
    StatsMgr::instance().setMaxSampleAgeDefaultInternal(duration);
476
0
    StatsMgr::instance().setMaxSampleAgeAllInternal(duration);
477
0
    return (createAnswer(CONTROL_RESULT_SUCCESS,
478
0
                         "All statistics duration limit are set."));
479
0
}
480
481
ConstElementPtr
482
0
StatsMgr::statisticSetMaxSampleCountAllHandler(const ConstElementPtr& params) {
483
0
    string error;
484
0
    uint32_t max_samples;
485
0
    if (!StatsMgr::getStatMaxSamples(params, max_samples, error)) {
486
0
        return (createAnswer(CONTROL_RESULT_ERROR, error));
487
0
    }
488
0
    if (max_samples == 0) {
489
0
        error = "'max-samples' parameter must not be zero";
490
0
        return (createAnswer(CONTROL_RESULT_ERROR, error));
491
0
    }
492
0
    MultiThreadingLock lock(*mutex_);
493
0
    StatsMgr::instance().setMaxSampleCountDefaultInternal(max_samples);
494
0
    StatsMgr::instance().setMaxSampleCountAllInternal(max_samples);
495
0
    return (createAnswer(CONTROL_RESULT_SUCCESS,
496
0
                         "All statistics count limit are set."));
497
0
}
498
499
bool
500
StatsMgr::getStatName(const ConstElementPtr& params,
501
                      string& name,
502
1
                      string& reason) {
503
1
    if (!params) {
504
1
        reason = "Missing mandatory 'name' parameter.";
505
1
        return (false);
506
1
    }
507
0
    ConstElementPtr stat_name = params->get("name");
508
0
    if (!stat_name) {
509
0
        reason = "Missing mandatory 'name' parameter.";
510
0
        return (false);
511
0
    }
512
0
    if (stat_name->getType() != Element::string) {
513
0
        reason = "'name' parameter expected to be a string.";
514
0
        return (false);
515
0
    }
516
0
    name = stat_name->stringValue();
517
0
    return (true);
518
0
}
519
520
bool
521
StatsMgr::getStatDuration(const ConstElementPtr& params,
522
                          StatsDuration& duration,
523
0
                          string& reason) {
524
0
    if (!params) {
525
0
        reason = "Missing mandatory 'duration' parameter.";
526
0
        return (false);
527
0
    }
528
0
    ConstElementPtr stat_duration = params->get("duration");
529
0
    if (!stat_duration) {
530
0
        reason = "Missing mandatory 'duration' parameter.";
531
0
        return (false);
532
0
    }
533
0
    duration = std::chrono::seconds(stat_duration->intValue());
534
0
    return (true);
535
0
}
536
537
bool
538
StatsMgr::getStatMaxSamples(const ConstElementPtr& params,
539
                            uint32_t& max_samples,
540
0
                            string& reason) {
541
0
    if (!params) {
542
0
        reason = "Missing mandatory 'max-samples' parameter.";
543
0
        return (false);
544
0
    }
545
0
    ConstElementPtr stat_max_samples = params->get("max-samples");
546
0
    if (!stat_max_samples) {
547
0
        reason = "Missing mandatory 'max-samples' parameter.";
548
0
        return (false);
549
0
    }
550
0
    if (stat_max_samples->getType() != Element::integer) {
551
0
        reason = "'max-samples' parameter expected to be an integer.";
552
0
        return (false);
553
0
    }
554
0
    max_samples = stat_max_samples->intValue();
555
0
    return (true);
556
0
}
557
558
} // end of namespace stats
559
} // end of namespace isc