class StatsMgr : public boost::noncopyable {
public:
+ /// \brief Custom Counter
+ ///
+ /// This class represents custom statistics counters. Client class
+ /// may create unlimited number of counters. Such counters are
+ /// being stored in map in Statistics Manager and access using
+ /// unique string key.
+ class CustomCounter {
+ public:
+ /// \brief Constructor.
+ ///
+ /// This constructor sets counter name. This name is used in
+ /// log file to report value of each counter.
+ ///
+ /// \param name name of the counter used in log file.
+ CustomCounter(const std::string& name) :
+ counter_(0),
+ name_(name) { };
+
+ /// \brief Increment operator.
+ const CustomCounter& operator++() {
+ ++counter_;
+ return *this;
+ }
+
+ /// \brief Increment operator.
+ const CustomCounter& operator++(int) {
+ CustomCounter& this_counter(*this);
+ operator++();
+ return this_counter;
+ }
+
+ /// \brief Return counter value.
+ ///
+ /// Method returns counter value.
+ ///
+ /// \return counter value.
+ uint64_t getValue() const {
+ return counter_;
+ }
+
+ /// \brief Return counter name.
+ ///
+ /// Method returns counter name.
+ ///
+ /// \return counter name.
+ const std::string& getName() const {
+ return name_;
+ }
+ private:
+ /// \brief Default constructor.
+ ///
+ /// Default constrcutor is private because we don't want client
+ /// class to call it because we want client class to specify
+ /// counter's name.
+ CustomCounter() { };
+
+ uint64_t counter_; ///< Counter's value.
+ std::string name_; ///< Counter's name.
+ };
+
+ typedef typename boost::shared_ptr<CustomCounter> CustomCounterPtr;
+
/// DHCP packet exchange types.
enum ExchangeType {
XCHG_DO, ///< DHCPv4 DISCOVER-OFFER
typedef typename std::map<ExchangeType, ExchangeStatsPtr> ExchangesMap;
/// Iterator poiting to \ref ExchangesMap
typedef typename ExchangesMap::const_iterator ExchangesMapIterator;
+ /// Map containing custom counters.
+ typedef typename std::map<std::string, CustomCounterPtr> CustomCountersMap;
+ /// Iterator for \ref CustomCountersMap.
+ typedef typename CustomCountersMap::iterator CustomCountersMapIterator;
+
+ /// \brief Constructor.
+ StatsMgr()
+ : exchanges_(),
+ custom_counters_() {
+ }
/// \brief Specify new exchange type.
///
exchanges_[xchg_type] = ExchangeStatsPtr(new ExchangeStats(xchg_type));
}
+ /// \brief Add named custom uint64 counter.
+ ///
+ /// Method creates new named counter and stores in counter's map under
+ /// key specified here as short_name.
+ ///
+ /// \param short_name key to use to access counter in the map.
+ /// \param long_name name of the counter presented in the log file.
+ void addCustomCounter(const std::string& short_name,
+ const std::string& long_name) {
+ if (custom_counters_.find(short_name) != custom_counters_.end()) {
+ isc_throw(BadValue,
+ "Custom counter " << short_name << " already added.");
+ }
+ custom_counters_[short_name] =
+ CustomCounterPtr(new CustomCounter(long_name));
+ }
+
+ /// \brief Return specified counter.
+ ///
+ /// Method returns specified counter.
+ ///
+ /// \param counter_key key poiting to the counter in the counters map.
+ /// \return pointer to specified counter object.
+ CustomCounterPtr getCounter(const std::string& counter_key) {
+ CustomCountersMapIterator it = custom_counters_.find(counter_key);
+ if (it == custom_counters_.end()) {
+ isc_throw(BadValue,
+ "Custom counter " << counter_key << "does not exist");
+ }
+ return it->second;
+ }
+
+ /// \brief Increment specified counter.
+ ///
+ /// Increement counter value by one.
+ ///
+ /// \param counter_key key poitinh to the counter in the counters map.
+ /// \return pointer to specified counter after incrementation.
+ const CustomCounter& IncrementCounter(const std::string& counter_key) {
+ CustomCounterPtr counter = getCounter(counter_key);
+ return ++(*counter);
+ }
+
/// \brief Adds new packet to the sent packets list.
///
/// Method adds new packet to the sent packets list.
ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
return xchg_stats->getRcvdPacketsNum();
}
+
private:
/// \brief Return exchange stats object for given exchange type
///
return xchg_stats;
}
- ExchangesMap exchanges_; ///< Map of exchange types.
+ ExchangesMap exchanges_; ///< Map of exchange types.
+ CustomCountersMap custom_counters_; ///< Map with custom counters.
};
} // namespace perfdhcp
EXPECT_GT(stats_mgr->getSquareSumDelay(StatsMgr4::XCHG_DO), 1);
}
+TEST_F(StatsMgrTest, CustomCounters) {
+ boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
+
+ // Specify counter keys and names.
+ const std::string too_short_key("tooshort");
+ const std::string too_short_name("Too short packets");
+ const std::string too_late_key("toolate");
+ const std::string too_late_name("Packets sent too late");
+
+ // Add two custom counters.
+ stats_mgr->addCustomCounter(too_short_key, too_short_name);
+ stats_mgr->addCustomCounter(too_late_key, too_late_name);
+
+ // Increment one of the counters 10 times.
+ const uint64_t tooshort_num = 10;
+ for (uint64_t i = 0; i < tooshort_num; ++i) {
+ stats_mgr->IncrementCounter(too_short_key);
+ }
+
+ // Increment another counter by 5 times.
+ const uint64_t toolate_num = 5;
+ for (uint64_t i = 0; i < toolate_num; ++i) {
+ stats_mgr->IncrementCounter(too_late_key);
+ }
+
+ // Check counter's current value and name.
+ StatsMgr4::CustomCounterPtr tooshort_counter =
+ stats_mgr->getCounter(too_short_key);
+ EXPECT_EQ(too_short_name, tooshort_counter->getName());
+ EXPECT_EQ(tooshort_num, tooshort_counter->getValue());
+
+ // Check counter's current value and name.
+ StatsMgr4::CustomCounterPtr toolate_counter =
+ stats_mgr->getCounter(too_late_key);
+ EXPECT_EQ(too_late_name, toolate_counter->getName());
+ EXPECT_EQ(toolate_num, toolate_counter->getValue());
+}
+
}