logger-factory.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2017, Regents of the University of California,
4  * Arizona Board of Regents,
5  * Colorado State University,
6  * University Pierre & Marie Curie, Sorbonne University,
7  * Washington University in St. Louis,
8  * Beijing Institute of Technology,
9  * The University of Memphis.
10  *
11  * This file is part of NFD (Named Data Networking Forwarding Daemon).
12  * See AUTHORS.md for complete list of NFD authors and contributors.
13  *
14  * NFD is free software: you can redistribute it and/or modify it under the terms
15  * of the GNU General Public License as published by the Free Software Foundation,
16  * either version 3 of the License, or (at your option) any later version.
17  *
18  * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20  * PURPOSE. See the GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "logger-factory.hpp"
27 
28 #include <ndn-cxx/util/logging.hpp>
29 
30 #include <boost/algorithm/string/case_conv.hpp>
31 #include <boost/range/adaptor/map.hpp>
32 
33 #include <iostream>
34 
35 #ifdef HAVE_CUSTOM_LOGGER
36 #error "This file should not be compiled when custom logger is used"
37 #endif
38 
39 namespace nfd {
40 
41 NFD_LOG_INIT("LoggerFactory");
42 
43 LoggerFactory&
45 {
46  static LoggerFactory globalLoggerFactory;
47 
48  return globalLoggerFactory;
49 }
50 
51 LoggerFactory::LoggerFactory()
52  : m_defaultLevel(LOG_INFO)
53 {
54  m_levelNames["NONE"] = LOG_NONE;
55  m_levelNames["ERROR"] = LOG_ERROR;
56  m_levelNames["WARN"] = LOG_WARN;
57  m_levelNames["INFO"] = LOG_INFO;
58  m_levelNames["DEBUG"] = LOG_DEBUG;
59  m_levelNames["TRACE"] = LOG_TRACE;
60  m_levelNames["ALL"] = LOG_ALL;
61 
62  // Let ndn-cxx logging facility initialize Boost.Log backend,
63  // so that only one sink is attached to Boost.Log core.
64  ndn::util::Logging::setDestination(std::clog);
65 }
66 
67 LoggerFactory::~LoggerFactory()
68 {
69  ndn::util::Logging::flush();
70 }
71 
72 void
74 {
75  config.addSectionHandler("log", bind(&LoggerFactory::onConfig, this, _1, _2, _3));
76 }
77 
79 LoggerFactory::parseLevel(const std::string& level)
80 {
81  std::string upperLevel = boost::to_upper_copy(level);
82 
83  // std::cerr << "parsing level: " << upperLevel << std::endl;;
84  // std::cerr << "# levels: " << m_levelNames.size() << std::endl;
85  // std::cerr << m_levelNames.begin()->first << std::endl;
86 
87  LevelMap::const_iterator levelIt = m_levelNames.find(upperLevel);
88  if (levelIt != m_levelNames.end()) {
89  return levelIt->second;
90  }
91  try {
92  uint32_t levelNo = boost::lexical_cast<uint32_t>(level);
93 
94  if ((boost::lexical_cast<uint32_t>(LOG_NONE) <= levelNo &&
95  levelNo <= boost::lexical_cast<uint32_t>(LOG_TRACE)) ||
96  levelNo == LOG_ALL) {
97  return static_cast<LogLevel>(levelNo);
98  }
99  }
100  catch (const boost::bad_lexical_cast& error) {
101  }
102 
103  BOOST_THROW_EXCEPTION(LoggerFactory::Error("Unsupported logging level \"" + level + "\""));
104 }
105 
106 LogLevel
107 LoggerFactory::extractLevel(const ConfigSection& item, const std::string& key)
108 {
109  std::string levelString;
110  try {
111  levelString = item.get_value<std::string>();
112  }
113  catch (const boost::property_tree::ptree_error& error) {
114  }
115 
116  if (levelString.empty()) {
117  BOOST_THROW_EXCEPTION(LoggerFactory::Error("No logging level found for option \"" + key + "\""));
118  }
119 
120  return parseLevel(levelString);
121 }
122 
123 void
125  bool isDryRun,
126  const std::string& filename)
127 {
128  // log
129  // {
130  // ; default_level specifies the logging level for modules
131  // ; that are not explicitly named. All debugging levels
132  // ; listed above the selected value are enabled.
133  //
134  // default_level INFO
135  //
136  // ; You may also override the default for specific modules:
137  //
138  // FibManager DEBUG
139  // Forwarder WARN
140  // }
141 
142  if (!isDryRun) {
143  ConfigSection::const_assoc_iterator item = section.find("default_level");
144  if (item != section.not_found()) {
145  LogLevel level = extractLevel(item->second, "default_level");
146  setDefaultLevel(level);
147  }
148  else {
149  setDefaultLevel(LOG_INFO);
150  }
151  }
152 
153  for (const auto& i : section) {
154  LogLevel level = extractLevel(i.second, i.first);
155 
156  if (i.first == "default_level") {
157  // do nothing
158  }
159  else {
160  std::unique_lock<std::mutex> lock(m_loggersGuard);
161  LoggerMap::iterator loggerIt = m_loggers.find(i.first);
162  if (loggerIt == m_loggers.end()) {
163  lock.unlock();
164  NFD_LOG_DEBUG("Failed to configure logging level for module \"" <<
165  i.first << "\" (module not found)");
166  }
167  else if (!isDryRun) {
168  loggerIt->second.setLogLevel(level);
169  lock.unlock();
170  NFD_LOG_DEBUG("Changing level for module " << i.first << " to " << level);
171  }
172  }
173  }
174 }
175 
176 void
177 LoggerFactory::setDefaultLevel(LogLevel level)
178 {
179  // std::cerr << "changing to default_level " << level << std::endl;
180  std::lock_guard<std::mutex> lock(m_loggersGuard);
181 
182  m_defaultLevel = level;
183  for (auto&& logger : m_loggers) {
184  // std::cerr << "changing " << i->first << " to default " << m_defaultLevel << std::endl;
185  logger.second.setLogLevel(m_defaultLevel);
186  }
187 }
188 
189 void
190 LoggerFactory::flushBackend()
191 {
192  ndn::util::Logging::flush();
193 }
194 
195 Logger&
196 LoggerFactory::create(const std::string& moduleName)
197 {
198  return LoggerFactory::getInstance().createLogger(moduleName);
199 }
200 
201 Logger&
202 LoggerFactory::createLogger(const std::string& moduleName)
203 {
204  // std::cerr << "creating logger for " << moduleName
205  // << " with level " << m_defaultLevel << std::endl;
206 
207  std::lock_guard<std::mutex> lock(m_loggersGuard);
208 
209  std::pair<LoggerMap::iterator, bool> loggerIt =
210  m_loggers.insert(NameAndLogger(moduleName, Logger(moduleName, m_defaultLevel)));
211 
212  return loggerIt.first->second;
213 }
214 
215 std::list<std::string>
217 {
218  std::lock_guard<std::mutex> lock(m_loggersGuard);
219 
220  std::list<std::string> modules;
221  for (const auto& loggerName : m_loggers | boost::adaptors::map_keys) {
222  modules.push_back(loggerName);
223  }
224 
225  return modules;
226 }
227 
228 } // namespace nfd
void addSectionHandler(const std::string &sectionName, ConfigSectionHandler subscriber)
setup notification of configuration file sections
Definition: config-file.cpp:76
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:161
configuration file parsing utility
Definition: config-file.hpp:58
void setConfigFile(ConfigFile &config)
void onConfig(const ConfigSection &section, bool isDryRun, const std::string &filename)
static LoggerFactory & getInstance()
Table::const_iterator iterator
Definition: cs-internal.hpp:41
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
boost::property_tree::ptree ConfigSection
a config file section
Definition: config-file.hpp:37
static Logger & create(const std::string &moduleName)
#define NFD_LOG_INIT(name)
Definition: logger.hpp:122
LogLevel
indicates a log level
Definition: logger.hpp:42
provides logging for a module
Definition: logger.hpp:58
std::list< std::string > getModules() const