src: Implement packet statistics collection

refs: #2955, #2956

Change-Id: I57476a63562dbd378e566ad0280c89ccc5883e3e
diff --git a/src/hello-protocol.cpp b/src/hello-protocol.cpp
index 4a995de..2e17e16 100644
--- a/src/hello-protocol.cpp
+++ b/src/hello-protocol.cpp
@@ -19,9 +19,9 @@
  *
  **/
 
+#include "hello-protocol.hpp"
 #include "nlsr.hpp"
 #include "lsdb.hpp"
-#include "hello-protocol.hpp"
 #include "utility/name-helper.hpp"
 #include "logger.hpp"
 
@@ -47,6 +47,9 @@
                                                  this, _1),
                                        std::bind(&HelloProtocol::processInterestTimedOut,
                                                  this, _1));
+
+  // increment SENT_HELLO_INTEREST
+  hpIncrementSignal(Statistics::PacketType::SENT_HELLO_INTEREST);
 }
 
 void
@@ -85,12 +88,17 @@
 {
   // interest name: /<neighbor>/NLSR/INFO/<router>
   const ndn::Name interestName = interest.getName();
+
+  // increment RCV_HELLO_INTEREST
+  hpIncrementSignal(Statistics::PacketType::RCV_HELLO_INTEREST);
+
   _LOG_DEBUG("Interest Received for Name: " << interestName);
   if (interestName.get(-2).toUri() != INFO_COMPONENT) {
     _LOG_DEBUG("INFO_COMPONENT not found or interestName: " << interestName
                << " does not match expression");
     return;
   }
+
   ndn::Name neighbor;
   neighbor.wireDecode(interestName.get(-1).blockFromValue());
   _LOG_DEBUG("Neighbor: " << neighbor);
@@ -103,6 +111,8 @@
     m_nlsr.getKeyChain().sign(*data, m_nlsr.getDefaultCertName());
     _LOG_DEBUG("Sending out data for name: " << interest.getName());
     m_nlsr.getNlsrFace().put(*data);
+    // increment SENT_HELLO_DATA
+    hpIncrementSignal(Statistics::PacketType::SENT_HELLO_DATA);
 
     auto adjacent = m_nlsr.getAdjacencyList().findAdjacent(neighbor);
     // If this neighbor was previously inactive, send our own hello interest, too
@@ -209,6 +219,8 @@
       }
     }
   }
+  // increment RCV_HELLO_DATA
+  hpIncrementSignal(Statistics::PacketType::RCV_HELLO_DATA);
 }
 
   // Simply logs a debug message that the content could not be
diff --git a/src/hello-protocol.hpp b/src/hello-protocol.hpp
index 808b843..dbc12d0 100644
--- a/src/hello-protocol.hpp
+++ b/src/hello-protocol.hpp
@@ -22,8 +22,10 @@
 #ifndef NLSR_HELLO_PROTOCOL_HPP
 #define NLSR_HELLO_PROTOCOL_HPP
 
+#include "statistics.hpp"
 #include "test-access-control.hpp"
 
+#include <ndn-cxx/util/signal.hpp>
 #include <ndn-cxx/face.hpp>
 #include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
@@ -93,6 +95,8 @@
   void
   processInterest(const ndn::Name& name, const ndn::Interest& interest);
 
+  ndn::util::signal::Signal<HelloProtocol, Statistics::PacketType> hpIncrementSignal;
+
 private:
   void
   processInterestTimedOut(const ndn::Interest& interest);
diff --git a/src/lsdb.cpp b/src/lsdb.cpp
index b71b48e..5cfc783 100644
--- a/src/lsdb.cpp
+++ b/src/lsdb.cpp
@@ -29,8 +29,6 @@
 #include <ndn-cxx/security/signing-helpers.hpp>
 #include <ndn-cxx/util/segment-fetcher.hpp>
 
-#include <string>
-
 namespace nlsr {
 
 INIT_LOGGER("Lsdb");
@@ -961,6 +959,9 @@
 Lsdb::expressInterest(const ndn::Name& interestName, uint32_t timeoutCount,
                       steady_clock::TimePoint deadline)
 {
+  // increment SENT_LSA_INTEREST
+  lsaIncrementSignal(Statistics::PacketType::SENT_LSA_INTEREST);
+
   if (deadline == DEFAULT_LSA_RETRIEVAL_DEADLINE) {
     deadline = steady_clock::now() + ndn::time::seconds(static_cast<int>(LSA_REFRESH_TIME_MAX));
   }
@@ -991,11 +992,28 @@
                                    std::bind(&Lsdb::afterFetchLsa, this, _1, interestName),
                                    std::bind(&Lsdb::onFetchLsaError, this, _1, _2, interestName,
                                              timeoutCount, deadline, lsaName, seqNo));
+  // increment a specific SENT_LSA_INTEREST
+  std::string typeLSA = interestName[-2].toUri();
+  if (typeLSA == AdjLsa::TYPE_STRING) {
+    lsaIncrementSignal(Statistics::PacketType::SENT_ADJ_LSA_INTEREST);
+  }
+  else if (typeLSA == CoordinateLsa::TYPE_STRING) {
+    lsaIncrementSignal(Statistics::PacketType::SENT_COORD_LSA_INTEREST);
+  }
+  else if (typeLSA == NameLsa::TYPE_STRING) {
+    lsaIncrementSignal(Statistics::PacketType::SENT_NAME_LSA_INTEREST);
+  }
+  else {
+    _LOG_ERROR("typeLSA " + typeLSA + " not recognized; failed Statistics::PacketType conversion");
+  }
 }
 
 void
 Lsdb::processInterest(const ndn::Name& name, const ndn::Interest& interest)
 {
+  // increment RCV_LSA_INTEREST
+  lsaIncrementSignal(Statistics::PacketType::RCV_LSA_INTEREST);
+
   const ndn::Name& interestName(interest.getName());
   _LOG_DEBUG("Interest received for LSA: " << interestName);
 
@@ -1014,7 +1032,6 @@
 
     std::string interestedLsType = interestName[-2].toUri();
 
-    // Passes the Interest off to the appropriate subprocessor
     if (interestedLsType == NameLsa::TYPE_STRING) {
       processInterestForNameLsa(interest, originRouter.append(interestedLsType), seqNo);
     }
@@ -1027,6 +1044,7 @@
     else {
       _LOG_WARN("Received unrecognized LSA type: " << interestedLsType);
     }
+    lsaIncrementSignal(Statistics::PacketType::SENT_LSA_DATA);
   }
 }
 
@@ -1056,13 +1074,16 @@
                                 const ndn::Name& lsaKey,
                                 uint64_t seqNo)
 {
-
+  // increment RCV_NAME_LSA_INTEREST
+  lsaIncrementSignal(Statistics::PacketType::RCV_NAME_LSA_INTEREST);
   _LOG_DEBUG("nameLsa interest " << interest << " received");
   NameLsa*  nameLsa = m_nlsr.getLsdb().findNameLsa(lsaKey);
   if (nameLsa != 0) {
     if (nameLsa->getLsSeqNo() == seqNo) {
       std::string content = nameLsa->getData();
       putLsaData(interest,content);
+      // increment SENT_NAME_LSA_DATA
+      lsaIncrementSignal(Statistics::PacketType::SENT_NAME_LSA_DATA);
     }
     else {
       _LOG_TRACE("SeqNo for nameLsa does not match");
@@ -1087,12 +1108,16 @@
     _LOG_ERROR("Received interest for an adjacency LSA when hyperbolic routing is enabled");
   }
 
+  // increment RCV_ADJ_LSA_INTEREST
+  lsaIncrementSignal(Statistics::PacketType::RCV_ADJ_LSA_INTEREST);
   _LOG_DEBUG("AdjLsa interest " << interest << " received");
   AdjLsa* adjLsa = m_nlsr.getLsdb().findAdjLsa(lsaKey);
   if (adjLsa != 0) {
     if (adjLsa->getLsSeqNo() == seqNo) {
       std::string content = adjLsa->getData();
       putLsaData(interest,content);
+      // increment SENT_ADJ_LSA_DATA
+      lsaIncrementSignal(Statistics::PacketType::SENT_ADJ_LSA_DATA);
     }
     else {
       _LOG_TRACE("SeqNo for AdjLsa does not match");
@@ -1117,12 +1142,16 @@
     _LOG_ERROR("Received Interest for a coordinate LSA when link-state routing is enabled");
   }
 
+  // increment RCV_COORD_LSA_INTEREST
+  lsaIncrementSignal(Statistics::PacketType::RCV_COORD_LSA_INTEREST);
   _LOG_DEBUG("CoordinateLsa interest " << interest << " received");
   CoordinateLsa* corLsa = m_nlsr.getLsdb().findCoordinateLsa(lsaKey);
   if (corLsa != 0) {
     if (corLsa->getLsSeqNo() == seqNo) {
       std::string content = corLsa->getData();
       putLsaData(interest,content);
+      // increment SENT_COORD_LSA_DATA
+      lsaIncrementSignal(Statistics::PacketType::SENT_COORD_LSA_DATA);
     }
     else {
       _LOG_TRACE("SeqNo for CoordinateLsa does not match");
@@ -1166,6 +1195,9 @@
     else {
       _LOG_WARN("Received unrecognized LSA Type: " << interestedLsType);
     }
+
+    // increment RCV_LSA_DATA
+    lsaIncrementSignal(Statistics::PacketType::RCV_LSA_DATA);
   }
 }
 
@@ -1173,6 +1205,8 @@
 Lsdb::processContentNameLsa(const ndn::Name& lsaKey,
                             uint64_t lsSeqNo, std::string& dataContent)
 {
+  // increment RCV_NAME_LSA_DATA
+  lsaIncrementSignal(Statistics::PacketType::RCV_NAME_LSA_DATA);
   if (isNameLsaNew(lsaKey, lsSeqNo)) {
     NameLsa nameLsa;
     if (nameLsa.initializeFromContent(dataContent)) {
@@ -1188,6 +1222,8 @@
 Lsdb::processContentAdjacencyLsa(const ndn::Name& lsaKey,
                                  uint64_t lsSeqNo, std::string& dataContent)
 {
+  // increment RCV_ADJ_LSA_DATA
+  lsaIncrementSignal(Statistics::PacketType::RCV_ADJ_LSA_DATA);
   if (isAdjLsaNew(lsaKey, lsSeqNo)) {
     AdjLsa adjLsa;
     if (adjLsa.initializeFromContent(dataContent)) {
@@ -1203,6 +1239,8 @@
 Lsdb::processContentCoordinateLsa(const ndn::Name& lsaKey,
                                   uint64_t lsSeqNo, std::string& dataContent)
 {
+  // increment RCV_COORD_LSA_DATA
+  lsaIncrementSignal(Statistics::PacketType::RCV_COORD_LSA_DATA);
   if (isCoordinateLsaNew(lsaKey, lsSeqNo)) {
     CoordinateLsa corLsa;
     if (corLsa.initializeFromContent(dataContent)) {
diff --git a/src/lsdb.hpp b/src/lsdb.hpp
index 2b182bd..bb0b9d8 100644
--- a/src/lsdb.hpp
+++ b/src/lsdb.hpp
@@ -27,6 +27,14 @@
 #include "sequencing-manager.hpp"
 #include "test-access-control.hpp"
 #include "communication/sync-logic-handler.hpp"
+#include "statistics.hpp"
+
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/util/signal.hpp>
+#include <ndn-cxx/util/time.hpp>
+
+#include <utility>
+#include <boost/cstdint.hpp>
 
 #include <utility>
 #include <boost/cstdint.hpp>
@@ -374,6 +382,8 @@
 public:
   static const ndn::Name::Component NAME_COMPONENT;
 
+  ndn::util::signal::Signal<Lsdb, Statistics::PacketType> lsaIncrementSignal;
+
 private:
   Nlsr& m_nlsr;
   ndn::Scheduler& m_scheduler;
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index 55d426a..70648e3 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -81,6 +81,7 @@
   , m_nfdRibCommandProcessor(m_localhostDispatcher,
                              m_namePrefixList,
                              m_nlsrLsdb)
+  , m_statsCollector(m_nlsrLsdb, m_helloProtocol)
   , m_faceMonitor(m_nlsrFace)
   , m_firstHelloInterval(FIRST_HELLO_INTERVAL_DEFAULT)
 {
diff --git a/src/nlsr.hpp b/src/nlsr.hpp
index 1a3432a..54af8b4 100644
--- a/src/nlsr.hpp
+++ b/src/nlsr.hpp
@@ -38,6 +38,7 @@
 #include "update/prefix-update-processor.hpp"
 #include "update/nfd-rib-command-processor.hpp"
 #include "utility/name-helper.hpp"
+#include "stats-collector.hpp"
 
 #include <stdexcept>
 
@@ -376,6 +377,11 @@
   canonizeNeighborUris(std::list<Adjacent>::iterator currentNeighbor,
                        std::function<void(std::list<Adjacent>::iterator)> then);
 
+  StatsCollector&
+  getStatsCollector()
+  {
+    return m_statsCollector;
+  }
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   void
@@ -470,6 +476,7 @@
   ndn::Name m_defaultCertName;
   update::PrefixUpdateProcessor m_prefixUpdateProcessor;
   update::NfdRibCommandProcessor m_nfdRibCommandProcessor;
+  StatsCollector m_statsCollector;
 
   ndn::nfd::FaceMonitor m_faceMonitor;
 
diff --git a/src/statistics.cpp b/src/statistics.cpp
new file mode 100644
index 0000000..f5f5516
--- /dev/null
+++ b/src/statistics.cpp
@@ -0,0 +1,101 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2017,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "statistics.hpp"
+#include "nlsr.hpp"
+#include "utility/name-helper.hpp"
+
+namespace nlsr {
+
+size_t
+Statistics::get(PacketType type) const
+{
+  std::map<PacketType,int>::const_iterator it = m_packetCounter.find(type);
+  if(it != m_packetCounter.end())
+  {
+    return it->second;
+  }
+  else
+  {
+    return 0;
+  }
+}
+
+void
+Statistics::increment(PacketType type)
+{
+  m_packetCounter[type]++;
+}
+
+void
+Statistics::resetAll()
+{
+  for (auto&& it : m_packetCounter )
+  {
+    it.second = 0;
+  }
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Statistics& stats)
+{
+  using PacketType = Statistics::PacketType;
+
+  os << "++++++++++++++++++++++++++++++++++++++++\n"
+     << "+                                      +\n"
+     << "+              Statistics              +\n"
+     << "+                                      +\n"
+     << "++++++++++++++++++++++++++++++++++++++++\n"
+     << "HELLO PROTOCOL\n"
+     << "    Sent Hello Interests: "              << stats.get(PacketType::SENT_HELLO_INTEREST) << "\n"
+     << "    Sent Hello Data: "                   << stats.get(PacketType::SENT_HELLO_DATA) << "\n"
+     << "\n"
+     << "    Received Hello Interests: "          << stats.get(PacketType::RCV_HELLO_INTEREST) << "\n"
+     << "    Received Hello Data: "               << stats.get(PacketType::RCV_HELLO_DATA) << "\n"
+     << "\n"
+     << "LSDB\n"
+     << "    Total Sent LSA Interests: "          << stats.get(PacketType::SENT_LSA_INTEREST) << "\n"
+     << "    Total Received LSA Interests: "      << stats.get(PacketType::RCV_LSA_INTEREST) << "\n"
+     << "\n"
+     << "    Total Sent LSA Data: "               << stats.get(PacketType::SENT_LSA_DATA) << "\n"
+     << "    Total Received LSA Data: "           << stats.get(PacketType::RCV_LSA_DATA) << "\n"
+     << "\n"
+     << "    Sent Adjacency LSA Interests: "      << stats.get(PacketType::SENT_ADJ_LSA_INTEREST) << "\n"
+     << "    Sent Coordinate LSA Interests: "     << stats.get(PacketType::SENT_COORD_LSA_INTEREST) << "\n"
+     << "    Sent Name LSA Interests: "           << stats.get(PacketType::SENT_NAME_LSA_INTEREST) << "\n"
+     << "\n"
+     << "    Received Adjacency LSA Interests: "  << stats.get(PacketType::RCV_ADJ_LSA_INTEREST) << "\n"
+     << "    Received Coordinate LSA Interests: " << stats.get(PacketType::RCV_COORD_LSA_INTEREST) << "\n"
+     << "    Received Name LSA Interests: "       << stats.get(PacketType::RCV_NAME_LSA_INTEREST) << "\n"
+     << "\n"
+     << "    Sent Adjacency LSA Data: "           << stats.get(PacketType::SENT_ADJ_LSA_DATA) << "\n"
+     << "    Sent Coordinate LSA Data: "          << stats.get(PacketType::SENT_COORD_LSA_DATA) << "\n"
+     << "    Sent Name LSA Data: "                << stats.get(PacketType::SENT_NAME_LSA_DATA) << "\n"
+     << "\n"
+     << "    Received Adjacency LSA Data: "       << stats.get(PacketType::RCV_ADJ_LSA_DATA) << "\n"
+     << "    Received Coordinate LSA Data: "      << stats.get(PacketType::RCV_COORD_LSA_DATA) << "\n"
+     << "    Received Name LSA Data: "            << stats.get(PacketType::RCV_NAME_LSA_DATA) << "\n"
+     << "++++++++++++++++++++++++++++++++++++++++\n";
+
+  return os;
+}
+
+} // namespace nlsr
diff --git a/src/statistics.hpp b/src/statistics.hpp
new file mode 100644
index 0000000..435938f
--- /dev/null
+++ b/src/statistics.hpp
@@ -0,0 +1,80 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2017,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NLSR_STATISTICS_HPP
+#define NLSR_STATISTICS_HPP
+
+#include <map>
+
+namespace nlsr {
+
+class Statistics
+{
+
+public:
+  enum class PacketType {
+    SENT_HELLO_INTEREST,
+    SENT_HELLO_DATA,
+    RCV_HELLO_INTEREST,
+    RCV_HELLO_DATA,
+    SENT_LSA_INTEREST,
+    SENT_ADJ_LSA_INTEREST,
+    SENT_COORD_LSA_INTEREST,
+    SENT_NAME_LSA_INTEREST,
+    SENT_LSA_DATA,
+    SENT_ADJ_LSA_DATA,
+    SENT_COORD_LSA_DATA,
+    SENT_NAME_LSA_DATA,
+    RCV_LSA_INTEREST,
+    RCV_ADJ_LSA_INTEREST,
+    RCV_COORD_LSA_INTEREST,
+    RCV_NAME_LSA_INTEREST,
+    RCV_LSA_DATA,
+    RCV_ADJ_LSA_DATA,
+    RCV_COORD_LSA_DATA,
+    RCV_NAME_LSA_DATA
+  };
+
+  size_t
+  get(PacketType) const;
+
+  void
+  resetAll();
+
+  void
+  increment(PacketType);
+
+  const std::map<PacketType,int>&
+  getCounter() const
+  {
+    return m_packetCounter;
+  }
+
+private:
+  std::map<PacketType,int> m_packetCounter;
+};
+
+std::ostream&
+operator<<(std::ostream&, const Statistics& stats);
+
+} // namespace nlsr
+
+#endif // NLSR_STATISTICS_HPP
diff --git a/src/stats-collector.cpp b/src/stats-collector.cpp
new file mode 100644
index 0000000..cb179ec
--- /dev/null
+++ b/src/stats-collector.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2017,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "stats-collector.hpp"
+#include "logger.hpp"
+#include <fstream>
+
+namespace nlsr {
+
+StatsCollector::StatsCollector(Lsdb& lsdb, HelloProtocol& hp)
+  : m_lsdb(lsdb)
+  , m_hp(hp)
+{
+  m_lsaIncrementConn =
+  this->m_lsdb.lsaIncrementSignal.connect(std::bind(&StatsCollector::statsIncrement,
+                                                    this, _1));
+
+  m_helloIncrementConn =
+  this->m_hp.hpIncrementSignal.connect(std::bind(&StatsCollector::statsIncrement,
+                                                 this, _1));
+}
+
+StatsCollector::~StatsCollector()
+{
+  m_lsaIncrementConn.disconnect();
+  m_helloIncrementConn.disconnect();
+}
+
+void
+StatsCollector::statsIncrement(Statistics::PacketType pType)
+{
+  m_stats.increment(pType);
+}
+
+} // namespace nlsr
diff --git a/src/stats-collector.hpp b/src/stats-collector.hpp
new file mode 100644
index 0000000..a2be959
--- /dev/null
+++ b/src/stats-collector.hpp
@@ -0,0 +1,72 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2017,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NLSR_STATS_COLLECTOR_HPP
+#define NLSR_STATS_COLLECTOR_HPP
+
+#include "statistics.hpp"
+#include "lsdb.hpp"
+#include "hello-protocol.hpp"
+#include <ndn-cxx/util/signal.hpp>
+
+namespace nlsr {
+
+// brief: a class designed to handle statistical signals in nlsr
+
+class StatsCollector
+{
+public:
+
+  StatsCollector(Lsdb& lsdb, HelloProtocol& hp);
+
+  ~StatsCollector();
+
+  Statistics&
+  getStatistics()
+  {
+    return m_stats;
+  }
+
+private:
+
+  /*!
+   * \brief: increments a Statistics::PacketType
+   *
+   * \param: pType is an enum value corresponding to a Statistics::PacketType
+   *
+   * This takes in a Statistics::PacketType emitted by a signal and increments
+   * the value in m_stats.
+   */
+  void
+  statsIncrement(Statistics::PacketType pType);
+
+private:
+
+  Lsdb& m_lsdb;
+  HelloProtocol& m_hp;
+  Statistics m_stats;
+
+  ndn::util::signal::ScopedConnection m_lsaIncrementConn;
+  ndn::util::signal::ScopedConnection m_helloIncrementConn;
+};
+
+} // namespace nlsr
+
+#endif // NLSR_STATS_COLLECTOR_HPP