jni: Android-specific custom logger for NFD

Change-Id: I4d98a58b8320735e40b5da3d358b9c71b558d995
Refs: #2508
diff --git a/app/src/main/jni/nfd-android/custom-logger-factory.cpp b/app/src/main/jni/nfd-android/custom-logger-factory.cpp
new file mode 100644
index 0000000..f84a663
--- /dev/null
+++ b/app/src/main/jni/nfd-android/custom-logger-factory.cpp
@@ -0,0 +1,213 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014  Regents of the University of California,
+ *                     Arizona Board of Regents,
+ *                     Colorado State University,
+ *                     University Pierre & Marie Curie, Sorbonne University,
+ *                     Washington University in St. Louis,
+ *                     Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD 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.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "custom-logger-factory.hpp"
+
+namespace nfd {
+
+NFD_LOG_INIT("LoggerFactory");
+
+LoggerFactory&
+LoggerFactory::getInstance()
+{
+  static LoggerFactory globalLoggerFactory;
+
+  return globalLoggerFactory;
+}
+
+LoggerFactory::LoggerFactory()
+  : m_defaultLevel(LOG_INFO)
+{
+  m_levelNames["NONE"] = LOG_NONE;
+  m_levelNames["ERROR"] = LOG_ERROR;
+  m_levelNames["WARN"] = LOG_WARN;
+  m_levelNames["INFO"] = LOG_INFO;
+  m_levelNames["DEBUG"] = LOG_DEBUG;
+  m_levelNames["TRACE"] = LOG_TRACE;
+  m_levelNames["ALL"] = LOG_ALL;
+}
+
+void
+LoggerFactory::setConfigFile(ConfigFile& config)
+{
+  config.addSectionHandler("log", bind(&LoggerFactory::onConfig, this, _1, _2, _3));
+}
+
+LogLevel
+LoggerFactory::parseLevel(const std::string& level)
+{
+  std::string upperLevel = level;
+  boost::to_upper(upperLevel);
+
+  // std::cerr << "parsing level: " << upperLevel << std::endl;;
+  // std::cerr << "# levels: " << m_levelNames.size() << std::endl;
+  // std::cerr << m_levelNames.begin()->first << std::endl;
+
+  LevelMap::const_iterator levelIt = m_levelNames.find(upperLevel);
+  if (levelIt != m_levelNames.end())
+    {
+      return levelIt->second;
+    }
+  try
+    {
+      uint32_t levelNo = boost::lexical_cast<uint32_t>(level);
+
+      if ((boost::lexical_cast<uint32_t>(LOG_NONE) <= levelNo &&
+           levelNo <= boost::lexical_cast<uint32_t>(LOG_TRACE)) ||
+          levelNo == LOG_ALL)
+        {
+          return static_cast<LogLevel>(levelNo);
+        }
+    }
+  catch (const boost::bad_lexical_cast& error)
+    {
+    }
+  throw LoggerFactory::Error("Unsupported logging level \"" +
+                             level + "\"");
+}
+
+LogLevel
+LoggerFactory::extractLevel(const ConfigSection& item, const std::string& key)
+{
+  std::string levelString;
+  try
+    {
+      levelString = item.get_value<std::string>();
+    }
+  catch (const boost::property_tree::ptree_error& error)
+    {
+    }
+
+  if (levelString.empty())
+    {
+      throw LoggerFactory::Error("No logging level found for option \"" + key + "\"");
+    }
+
+  return parseLevel(levelString);
+}
+
+void
+LoggerFactory::onConfig(const ConfigSection& section,
+                        bool isDryRun,
+                        const std::string& filename)
+{
+// log
+// {
+//   ; default_level specifies the logging level for modules
+//   ; that are not explicitly named. All debugging levels
+//   ; listed above the selected value are enabled.
+//
+//   default_level INFO
+//
+//   ; You may also override the default for specific modules:
+//
+//   FibManager DEBUG
+//   Forwarder WARN
+// }
+
+  if (!isDryRun)
+    {
+      ConfigSection::const_assoc_iterator item = section.find("default_level");
+      if (item != section.not_found())
+        {
+          LogLevel level = extractLevel(item->second, "default_level");
+          setDefaultLevel(level);
+        }
+      else
+        {
+          setDefaultLevel(LOG_INFO);
+        }
+    }
+
+  for (ConfigSection::const_iterator item = section.begin();
+       item != section.end();
+       ++item)
+    {
+      LogLevel level = extractLevel(item->second, item->first);
+
+      if (item->first == "default_level")
+        {
+          // do nothing
+        }
+      else
+        {
+          LoggerMap::iterator loggerIt = m_loggers.find(item->first);
+          if (loggerIt == m_loggers.end())
+            {
+              NFD_LOG_DEBUG("Failed to configure logging level for module \"" <<
+                            item->first << "\" (module not found)");
+            }
+          else if (!isDryRun)
+            {
+              // std::cerr << "changing level for module " << item->first << " to " << level << std::endl;
+              loggerIt->second.setLogLevel(level);
+            }
+        }
+    }
+}
+
+void
+LoggerFactory::setDefaultLevel(LogLevel level)
+{
+  // std::cerr << "changing to default_level " << level << std::endl;
+
+  m_defaultLevel = level;
+  for (LoggerMap::iterator i = m_loggers.begin(); i != m_loggers.end(); ++i)
+    {
+      // std::cerr << "changing " << i->first << " to default " << m_defaultLevel << std::endl;
+      i->second.setLogLevel(m_defaultLevel);
+    }
+}
+
+Logger&
+LoggerFactory::create(const std::string& moduleName)
+{
+  return LoggerFactory::getInstance().createLogger(moduleName);
+}
+
+Logger&
+LoggerFactory::createLogger(const std::string& moduleName)
+{
+  // std::cerr << "creating logger for " << moduleName
+  //           << " with level " << m_defaultLevel << std::endl;
+
+  std::pair<LoggerMap::iterator, bool> loggerIt =
+    m_loggers.insert(NameAndLogger(moduleName, Logger(moduleName, m_defaultLevel)));
+
+  return loggerIt.first->second;
+}
+
+std::list<std::string>
+LoggerFactory::getModules() const
+{
+  std::list<std::string> modules;
+  for (LoggerMap::const_iterator i = m_loggers.begin(); i != m_loggers.end(); ++i)
+    {
+      modules.push_back(i->first);
+    }
+
+  return modules;
+}
+
+} // namespace nfd