Commit e76178c1 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[3793] Remaining features in Observation implemented.

parent 46f3bc40
#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);
}
......
......@@ -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;
};
};
......
......@@ -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());
}
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment