Browse Source

[3793] Remaining features in Observation implemented.

Tomek Mrugalski 10 years ago
parent
commit
e76178c19e
3 changed files with 104 additions and 86 deletions
  1. 17 12
      src/lib/stats/observation.cc
  2. 67 26
      src/lib/stats/observation.h
  3. 20 48
      src/lib/stats/tests/observation_unittest.cc

+ 17 - 12
src/lib/stats/observation.cc

@@ -1,4 +1,3 @@
-
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <stats/observation.h>
 #include <stats/observation.h>
 #include <cc/data.h>
 #include <cc/data.h>
@@ -11,23 +10,23 @@ using namespace boost::posix_time;
 namespace isc {
 namespace isc {
 namespace stats {
 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);
     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);
     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);
     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);
     setValue(value);
 }
 }
 
 
@@ -158,10 +157,13 @@ Observation::durationToText(StatsDuration dur) {
 isc::data::ConstElementPtr
 isc::data::ConstElementPtr
 Observation::getJSON() {
 Observation::getJSON() {
 
 
-    ElementPtr list = isc::data::Element::createList();
+    ElementPtr entry = isc::data::Element::createList(); // a single observation
     ElementPtr value;
     ElementPtr value;
     ElementPtr timestamp;
     ElementPtr timestamp;
 
 
+    /// @todo: Add support for retrieving more than one sample for a given
+    /// observation
+
     switch (type_) {
     switch (type_) {
     case STAT_INTEGER: {
     case STAT_INTEGER: {
         IntegerSample s = getInteger();
         IntegerSample s = getInteger();
@@ -191,8 +193,11 @@ Observation::getJSON() {
         isc_throw(InvalidStatType, "Unknown stat type: " << typeToText(type_));
         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);
     return (list);
 }
 }

+ 67 - 26
src/lib/stats/observation.h

@@ -41,7 +41,7 @@ public:
 /// implementations: boost::posix_time::{hours,minutes,seconds,millisec,nanosec}.
 /// implementations: boost::posix_time::{hours,minutes,seconds,millisec,nanosec}.
 /// For statistics purposes, the most appropriate choice seems to be milliseconds
 /// For statistics purposes, the most appropriate choice seems to be milliseconds
 /// precision, so we'll stick with that.
 /// 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.
 /// @defgroup stat_samples Specifies supported observation types.
 ///
 ///
@@ -99,23 +99,27 @@ class Observation {
 
 
     /// @brief Constructor for integer observations
     /// @brief Constructor for integer observations
     ///
     ///
+    /// @param name observation name
     /// @param value integer value observed.
     /// @param value integer value observed.
-    Observation(uint64_t value);
+    Observation(const std::string& name, uint64_t value);
 
 
     /// @brief Constructor for floating point observations
     /// @brief Constructor for floating point observations
     ///
     ///
+    /// @param name observation name
     /// @param value floating point value observed.
     /// @param value floating point value observed.
-    Observation(double value);
+    Observation(const std::string& name, double value);
 
 
     /// @brief Constructor for duration observations
     /// @brief Constructor for duration observations
     ///
     ///
+    /// @param name observation name
     /// @param value duration observed.
     /// @param value duration observed.
-    Observation(StatsDuration value);
+    Observation(const std::string& name, StatsDuration value);
 
 
     /// @brief Constructor for string observations
     /// @brief Constructor for string observations
     ///
     ///
+    /// @param name observation name
     /// @param value string observed.
     /// @param value string observed.
-    Observation(const std::string& value);
+    Observation(const std::string& name, const std::string& value);
 
 
     /// @brief Records absolute integer observation
     /// @brief Records absolute integer observation
     ///
     ///
@@ -178,65 +182,102 @@ class Observation {
 
 
     /// @brief Returns observed integer sample
     /// @brief Returns observed integer sample
     /// @return observed sample (value + timestamp)
     /// @return observed sample (value + timestamp)
+    /// @throw InvalidStatType if statistic is not integer
     IntegerSample getInteger();
     IntegerSample getInteger();
 
 
     /// @brief Returns observed float sample
     /// @brief Returns observed float sample
     /// @return observed sample (value + timestamp)
     /// @return observed sample (value + timestamp)
+    /// @throw InvalidStatType if statistic is not fp
     FloatSample getFloat();
     FloatSample getFloat();
 
 
     /// @brief Returns observed duration sample
     /// @brief Returns observed duration sample
     /// @return observed sample (value + timestamp)
     /// @return observed sample (value + timestamp)
+    /// @throw InvalidStatType if statistic is not time duration
     DurationSample getDuration();
     DurationSample getDuration();
 
 
     /// @brief Returns observed string sample
     /// @brief Returns observed string sample
     /// @return observed sample (value + timestamp)
     /// @return observed sample (value + timestamp)
+    /// @throw InvalidStatType if statistic is not a string
     StringSample getString();
     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();
     isc::data::ConstElementPtr getJSON();
 
 
+    /// @brief Converts statistic type to string
+    /// @return textual name of statistic type
     static std::string typeToText(Type 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);
     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);
     static std::string durationToText(StatsDuration dur);
 
 
+    /// @brief Returns observation name
+    std::string getName() {
+        return (name_);
+    }
+
  protected:
  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>
     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>
     template<typename SampleType, typename Storage>
     SampleType getValueInternal(Storage& storage, Type exp_type);
     SampleType getValueInternal(Storage& storage, Type exp_type);
 
 
+    /// @brief Observation (statistic) name
     std::string name_;
     std::string name_;
+
+    /// @brief Observation (statistic) type)
     Type 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_;
     std::list<IntegerSample> integer_samples_;
+
+    /// @brief Storage for floating point samples
     std::list<FloatSample> float_samples_;
     std::list<FloatSample> float_samples_;
+
+    /// @brief Storage for time duration samples
     std::list<DurationSample> duration_samples_;
     std::list<DurationSample> duration_samples_;
+
+    /// @brief Storage for string samples
     std::list<StringSample> string_samples_;
     std::list<StringSample> string_samples_;
+    /// @}
 };
 };
 
 
- typedef boost::shared_ptr<Observation> ObservationPtr;
+/// @brief Observation pointer
+typedef boost::shared_ptr<Observation> ObservationPtr;
 
 
 };
 };
 };
 };

+ 20 - 48
src/lib/stats/tests/observation_unittest.cc

@@ -35,10 +35,10 @@ namespace {
 class ObservationTest : public ::testing::Test {
 class ObservationTest : public ::testing::Test {
 public:
 public:
     ObservationTest()
     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;
     Observation a;
@@ -135,42 +135,6 @@ TEST_F(ObservationTest, addValue) {
     EXPECT_EQ("1234fiveSixSevenEight", d.getString().first);
     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 checks whether timing is reported properly.
 TEST_F(ObservationTest, timers) {
 TEST_F(ObservationTest, timers) {
     ptime min = microsec_clock::local_time();
     ptime min = microsec_clock::local_time();
@@ -197,8 +161,8 @@ TEST_F(ObservationTest, integerToJSON) {
 
 
     a.setValue(static_cast<uint64_t>(1234));
     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;
     std::cout << a.getJSON()->str() << std::endl;
     EXPECT_EQ(exp, a.getJSON()->str());
     EXPECT_EQ(exp, a.getJSON()->str());
@@ -212,8 +176,8 @@ TEST_F(ObservationTest, floatToJSON) {
     // No need to deal with infinite fractions in binary systems.
     // No need to deal with infinite fractions in binary systems.
     b.setValue(1234.5);
     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;
     std::cout << b.getJSON()->str() << std::endl;
     EXPECT_EQ(exp, b.getJSON()->str());
     EXPECT_EQ(exp, b.getJSON()->str());
@@ -226,8 +190,8 @@ TEST_F(ObservationTest, durationToJSON) {
     // 1 hour 2 minutes 3 seconds and 4 milliseconds
     // 1 hour 2 minutes 3 seconds and 4 milliseconds
     c.setValue(time_duration(1,2,3,4));
     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;
     std::cout << c.getJSON()->str() << std::endl;
     EXPECT_EQ(exp, c.getJSON()->str());
     EXPECT_EQ(exp, c.getJSON()->str());
@@ -240,8 +204,8 @@ TEST_F(ObservationTest, stringToJSON) {
     //
     //
     d.setValue("Lorem ipsum dolor sit amet");
     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;
     std::cout << d.getJSON()->str() << std::endl;
     EXPECT_EQ(exp, d.getJSON()->str());
     EXPECT_EQ(exp, d.getJSON()->str());
@@ -260,4 +224,12 @@ TEST_F(ObservationTest, reset) {
     EXPECT_EQ("", d.getString().first);
     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());
+}
+
 };
 };