summaryrefslogtreecommitdiffstats
path: root/src/lib/stats
diff options
context:
space:
mode:
authorTomek Mrugalski <tomasz@isc.org>2015-05-07 19:41:22 +0200
committerTomek Mrugalski <tomasz@isc.org>2015-05-07 19:41:22 +0200
commite76178c19ed93ee4171d075db11df5721eea599a (patch)
treea3ea4fd23e0cbac7c50df89df618d68f7d063858 /src/lib/stats
parent[3793] Observation class + unittests, skeleton impl of StatsMgr (diff)
downloadkea-e76178c19ed93ee4171d075db11df5721eea599a.tar.xz
kea-e76178c19ed93ee4171d075db11df5721eea599a.zip
[3793] Remaining features in Observation implemented.
Diffstat (limited to 'src/lib/stats')
-rw-r--r--src/lib/stats/observation.cc29
-rw-r--r--src/lib/stats/observation.h93
-rw-r--r--src/lib/stats/tests/observation_unittest.cc68
3 files changed, 104 insertions, 86 deletions
diff --git a/src/lib/stats/observation.cc b/src/lib/stats/observation.cc
index 72bd1559ce..019120200f 100644
--- a/src/lib/stats/observation.cc
+++ b/src/lib/stats/observation.cc
@@ -1,4 +1,3 @@
-
#include <boost/date_time/posix_time/posix_time.hpp>
#include <stats/observation.h>
#include <cc/data.h>
@@ -11,23 +10,23 @@ using namespace boost::posix_time;
namespace isc {
namespace stats {
-Observation::Observation(uint64_t value)
- :type_(STAT_INTEGER), max_samples_(1) {
+Observation::Observation(const std::string& name, uint64_t value)
+ :name_(name), type_(STAT_INTEGER) {
setValue(value);
}
-Observation::Observation(double value)
- :type_(STAT_FLOAT), max_samples_(1) {
+Observation::Observation(const std::string& name, double value)
+ :name_(name), type_(STAT_FLOAT) {
setValue(value);
}
-Observation::Observation(StatsDuration value)
- :type_(STAT_DURATION), max_samples_(1) {
+Observation::Observation(const std::string& name, StatsDuration value)
+ :name_(name), type_(STAT_DURATION) {
setValue(value);
}
-Observation::Observation(const std::string& value)
- :type_(STAT_STRING), max_samples_(1) {
+Observation::Observation(const std::string& name, const std::string& value)
+ :name_(name), type_(STAT_STRING) {
setValue(value);
}
@@ -158,10 +157,13 @@ Observation::durationToText(StatsDuration dur) {
isc::data::ConstElementPtr
Observation::getJSON() {
- ElementPtr list = isc::data::Element::createList();
+ ElementPtr entry = isc::data::Element::createList(); // a single observation
ElementPtr value;
ElementPtr timestamp;
+ /// @todo: Add support for retrieving more than one sample for a given
+ /// observation
+
switch (type_) {
case STAT_INTEGER: {
IntegerSample s = getInteger();
@@ -191,8 +193,11 @@ Observation::getJSON() {
isc_throw(InvalidStatType, "Unknown stat type: " << typeToText(type_));
};
- list->add(value);
- list->add(timestamp);
+ entry->add(value);
+ entry->add(timestamp);
+
+ ElementPtr list = isc::data::Element::createList(); // a single observation
+ list->add(entry);
return (list);
}
diff --git a/src/lib/stats/observation.h b/src/lib/stats/observation.h
index a3a3bf733c..9328ceb3c5 100644
--- a/src/lib/stats/observation.h
+++ b/src/lib/stats/observation.h
@@ -41,7 +41,7 @@ public:
/// implementations: boost::posix_time::{hours,minutes,seconds,millisec,nanosec}.
/// For statistics purposes, the most appropriate choice seems to be milliseconds
/// precision, so we'll stick with that.
-typedef boost::posix_time::millisec::time_duration StatsDuration;
+typedef boost::posix_time::microsec::time_duration StatsDuration;
/// @defgroup stat_samples Specifies supported observation types.
///
@@ -99,23 +99,27 @@ class Observation {
/// @brief Constructor for integer observations
///
+ /// @param name observation name
/// @param value integer value observed.
- Observation(uint64_t value);
+ Observation(const std::string& name, uint64_t value);
/// @brief Constructor for floating point observations
///
+ /// @param name observation name
/// @param value floating point value observed.
- Observation(double value);
+ Observation(const std::string& name, double value);
/// @brief Constructor for duration observations
///
+ /// @param name observation name
/// @param value duration observed.
- Observation(StatsDuration value);
+ Observation(const std::string& name, StatsDuration value);
/// @brief Constructor for string observations
///
+ /// @param name observation name
/// @param value string observed.
- Observation(const std::string& value);
+ Observation(const std::string& name, const std::string& value);
/// @brief Records absolute integer observation
///
@@ -178,65 +182,102 @@ class Observation {
/// @brief Returns observed integer sample
/// @return observed sample (value + timestamp)
+ /// @throw InvalidStatType if statistic is not integer
IntegerSample getInteger();
/// @brief Returns observed float sample
/// @return observed sample (value + timestamp)
+ /// @throw InvalidStatType if statistic is not fp
FloatSample getFloat();
/// @brief Returns observed duration sample
/// @return observed sample (value + timestamp)
+ /// @throw InvalidStatType if statistic is not time duration
DurationSample getDuration();
/// @brief Returns observed string sample
/// @return observed sample (value + timestamp)
+ /// @throw InvalidStatType if statistic is not a string
StringSample getString();
- const std::list<IntegerSample>& getIntegerList() {
- return (integer_samples_);
- }
-
- const std::list<FloatSample>& getFloatList() {
- return (float_samples_);
- }
-
- const std::list<DurationSample>& getDurationList() {
- return (duration_samples_);
- }
-
- const std::list<StringSample>& getStringList() {
- return (string_samples_);
- }
-
- /// Returns as a JSON structure
+ /// @brief Returns as a JSON structure
+ /// @return JSON structures representing all observations
isc::data::ConstElementPtr getJSON();
+ /// @brief Converts statistic type to string
+ /// @return textual name of statistic type
static std::string typeToText(Type type);
+ /// @brief Converts ptime structure to text
+ /// @return a string representing time
static std::string ptimeToText(boost::posix_time::ptime time);
+ /// @brief Converts StatsDuration to text
+ /// @return a string representing time
static std::string durationToText(StatsDuration dur);
+ /// @brief Returns observation name
+ std::string getName() {
+ return (name_);
+ }
+
protected:
+ /// @brief Records absolute sample (internal version)
+ ///
+ /// This method records an absolute value of an observation.
+ /// It is used by public methods to add sample to one of
+ /// available storages.
+ ///
+ /// @tparam SampleType type of sample (e.g. IntegerSample)
+ /// @tparam StorageType type of storage (e.g. list<IntegerSample>)
+ /// @param value observation to be recorded
+ /// @param storage observation will be stored here
+ /// @param exp_type expected observation type (used for sanity checking)
+ /// @throw InvalidStatType if observation type mismatches
template<typename SampleType, typename StorageType>
- void setValueInternal(SampleType value, StorageType& storage,
- Type exp_type);
+ void setValueInternal(SampleType value, StorageType& storage,
+ Type exp_type);
+ /// @brief Returns a sample
+ ///
+ /// @tparam SampleType type of sample (e.g. IntegerSample)
+ /// @tparam StorageType type of storage (e.g. list<IntegerSample>)
+ /// @param observation storage
+ /// @param exp_type expected observation type (used for sanity checking)
+ /// @throw InvalidStatType if observation type mismatches
+ /// @return Observed sample
template<typename SampleType, typename Storage>
SampleType getValueInternal(Storage& storage, Type exp_type);
+ /// @brief Observation (statistic) name
std::string name_;
+
+ /// @brief Observation (statistic) type)
Type type_;
- size_t max_samples_;
+ /// @defgroup samples_storage Storage for supported observations
+ ///
+ /// @brief The following containers serve as a storage for all supported
+ /// observation types.
+ ///
+ /// @{
+ /// @brief Storage for integer samples
std::list<IntegerSample> integer_samples_;
+
+ /// @brief Storage for floating point samples
std::list<FloatSample> float_samples_;
+
+ /// @brief Storage for time duration samples
std::list<DurationSample> duration_samples_;
+
+ /// @brief Storage for string samples
std::list<StringSample> string_samples_;
+ /// @}
};
- typedef boost::shared_ptr<Observation> ObservationPtr;
+/// @brief Observation pointer
+typedef boost::shared_ptr<Observation> ObservationPtr;
};
};
diff --git a/src/lib/stats/tests/observation_unittest.cc b/src/lib/stats/tests/observation_unittest.cc
index 32c3a86c64..c6d192a181 100644
--- a/src/lib/stats/tests/observation_unittest.cc
+++ b/src/lib/stats/tests/observation_unittest.cc
@@ -35,10 +35,10 @@ namespace {
class ObservationTest : public ::testing::Test {
public:
ObservationTest()
- :a(static_cast<uint64_t>(1234)), // integer
- b(12.34), // float
- c(millisec::time_duration(1,2,3,4)), // duration
- d("1234") { // string
+ :a("alpha", static_cast<uint64_t>(1234)), // integer
+ b("beta", 12.34), // float
+ c("gamma", millisec::time_duration(1,2,3,4)), // duration
+ d("delta", "1234") { // string
}
Observation a;
@@ -135,42 +135,6 @@ TEST_F(ObservationTest, addValue) {
EXPECT_EQ("1234fiveSixSevenEight", d.getString().first);
}
-// Observation will be extended to cover multiple samples of the same
-// property. That is not implemented for now, so regardless of the
-// number of recorded observation, always the last one is kept.
-TEST_F(ObservationTest, getLists) {
-
- // Let's record some data!
- for (int i = 0; i <= 42; ++i) {
-
- a.setValue(static_cast<uint64_t>(i));
- b.setValue(0.25*i);
- c.setValue(millisec::time_duration(0,0,i,0));
-
- std::stringstream tmp;
- tmp << i;
- d.setValue(tmp.str());
- }
-
- // Get the lists.
- std::list<IntegerSample> int_list = a.getIntegerList();
- std::list<FloatSample> float_list = b.getFloatList();
- std::list<DurationSample> dur_list = c.getDurationList();
- std::list<StringSample> str_list = d.getStringList();
-
- // Check that they have only one observation.
- ASSERT_EQ(1, int_list.size());
- ASSERT_EQ(1, float_list.size());
- ASSERT_EQ(1, dur_list.size());
- ASSERT_EQ(1, str_list.size());
-
- // Now check that that the recorded value is correct.
- EXPECT_EQ(42, int_list.begin()->first);
- EXPECT_EQ(10.5, float_list.begin()->first);
- EXPECT_EQ(millisec::time_duration(0,0,42,0), dur_list.begin()->first);
- EXPECT_EQ("42", str_list.begin()->first);
-}
-
// Test checks whether timing is reported properly.
TEST_F(ObservationTest, timers) {
ptime min = microsec_clock::local_time();
@@ -197,8 +161,8 @@ TEST_F(ObservationTest, integerToJSON) {
a.setValue(static_cast<uint64_t>(1234));
- std::string exp = "[ 1234, \""
- + Observation::ptimeToText(a.getInteger().second) + "\" ]";
+ std::string exp = "[ [ 1234, \""
+ + Observation::ptimeToText(a.getInteger().second) + "\" ] ]";
std::cout << a.getJSON()->str() << std::endl;
EXPECT_EQ(exp, a.getJSON()->str());
@@ -212,8 +176,8 @@ TEST_F(ObservationTest, floatToJSON) {
// No need to deal with infinite fractions in binary systems.
b.setValue(1234.5);
- std::string exp = "[ 1234.5, \""
- + Observation::ptimeToText(b.getFloat().second) + "\" ]";
+ std::string exp = "[ [ 1234.5, \""
+ + Observation::ptimeToText(b.getFloat().second) + "\" ] ]";
std::cout << b.getJSON()->str() << std::endl;
EXPECT_EQ(exp, b.getJSON()->str());
@@ -226,8 +190,8 @@ TEST_F(ObservationTest, durationToJSON) {
// 1 hour 2 minutes 3 seconds and 4 milliseconds
c.setValue(time_duration(1,2,3,4));
- std::string exp = "[ \"01:02:03.000004\", \""
- + Observation::ptimeToText(c.getDuration().second) + "\" ]";
+ std::string exp = "[ [ \"01:02:03.000004\", \""
+ + Observation::ptimeToText(c.getDuration().second) + "\" ] ]";
std::cout << c.getJSON()->str() << std::endl;
EXPECT_EQ(exp, c.getJSON()->str());
@@ -240,8 +204,8 @@ TEST_F(ObservationTest, stringToJSON) {
//
d.setValue("Lorem ipsum dolor sit amet");
- std::string exp = "[ \"Lorem ipsum dolor sit amet\", \""
- + Observation::ptimeToText(d.getString().second) + "\" ]";
+ std::string exp = "[ [ \"Lorem ipsum dolor sit amet\", \""
+ + Observation::ptimeToText(d.getString().second) + "\" ] ]";
std::cout << d.getJSON()->str() << std::endl;
EXPECT_EQ(exp, d.getJSON()->str());
@@ -260,4 +224,12 @@ TEST_F(ObservationTest, reset) {
EXPECT_EQ("", d.getString().first);
}
+// Checks whether an observation can keep its name.
+TEST_F(ObservationTest, names) {
+ EXPECT_EQ("alpha", a.getName());
+ EXPECT_EQ("beta", b.getName());
+ EXPECT_EQ("gamma", c.getName());
+ EXPECT_EQ("delta", d.getName());
+}
+
};