logging.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
22 #include "logging.hpp"
23 #include "logger.hpp"
24 
25 #include <boost/log/expressions.hpp>
26 #include <cstdlib>
27 #include <fstream>
28 
29 namespace ndn {
30 namespace util {
31 
33 
34 Logging&
35 Logging::get()
36 {
37  // Initialization of block-scope variables with static storage duration is thread-safe.
38  // See ISO C++ standard [stmt.dcl]/4
39  static Logging instance;
40  return instance;
41 }
42 
43 Logging::Logging()
44 {
45  this->setDestinationImpl(shared_ptr<std::ostream>(&std::clog, bind([]{})));
46 
47  const char* environ = std::getenv("NDN_LOG");
48  if (environ != nullptr) {
49  this->setLevelImpl(environ);
50  }
51 }
52 
53 void
54 Logging::addLoggerImpl(Logger& logger)
55 {
56  std::lock_guard<std::mutex> lock(m_mutex);
57 
58  const std::string& moduleName = logger.getModuleName();
59  m_loggers.insert({moduleName, &logger});
60 
61  auto levelIt = m_enabledLevel.find(moduleName);
62  if (levelIt == m_enabledLevel.end()) {
63  levelIt = m_enabledLevel.find("*");
64  }
65  LogLevel level = levelIt == m_enabledLevel.end() ? INITIAL_DEFAULT_LEVEL : levelIt->second;
66  logger.setLevel(level);
67 }
68 
69 #ifdef NDN_CXX_HAVE_TESTS
70 bool
71 Logging::removeLogger(Logger& logger)
72 {
73  const std::string& moduleName = logger.getModuleName();
74  auto range = m_loggers.equal_range(moduleName);
75  for (auto i = range.first; i != range.second; ++i) {
76  if (i->second == &logger) {
77  m_loggers.erase(i);
78  return true;
79  }
80  }
81  return false;
82 }
83 #endif // NDN_CXX_HAVE_TESTS
84 
85 void
86 Logging::setLevelImpl(const std::string& moduleName, LogLevel level)
87 {
88  std::lock_guard<std::mutex> lock(m_mutex);
89 
90  if (moduleName == "*") {
91  this->setDefaultLevel(level);
92  return;
93  }
94 
95  m_enabledLevel[moduleName] = level;
96  auto range = m_loggers.equal_range(moduleName);
97  for (auto i = range.first; i != range.second; ++i) {
98  i->second->setLevel(level);
99  }
100 }
101 
102 void
103 Logging::setDefaultLevel(LogLevel level)
104 {
105  m_enabledLevel.clear();
106  m_enabledLevel["*"] = level;
107 
108  for (auto i = m_loggers.begin(); i != m_loggers.end(); ++i) {
109  i->second->setLevel(level);
110  }
111 }
112 
113 void
114 Logging::setLevelImpl(const std::string& config)
115 {
116  std::stringstream ss(config);
117  std::string configModule;
118  while (std::getline(ss, configModule, ':')) {
119  size_t ind = configModule.find('=');
120  if (ind == std::string::npos) {
121  BOOST_THROW_EXCEPTION(std::invalid_argument("malformed logging config: '=' is missing"));
122  }
123 
124  std::string moduleName = configModule.substr(0, ind);
125  LogLevel level = parseLogLevel(configModule.substr(ind+1));
126 
127  this->setLevelImpl(moduleName, level);
128  }
129 }
130 
131 #ifdef NDN_CXX_HAVE_TESTS
132 std::string
133 Logging::getLevels() const
134 {
135  std::ostringstream os;
136 
137  auto defaultLevelIt = m_enabledLevel.find("*");
138  if (defaultLevelIt != m_enabledLevel.end()) {
139  os << "*=" << defaultLevelIt->second << ':';
140  }
141 
142  for (auto it = m_enabledLevel.begin(); it != m_enabledLevel.end(); ++it) {
143  if (it->first == "*") {
144  continue;
145  }
146  os << it->first << '=' << it->second << ':';
147  }
148 
149  std::string s = os.str();
150  if (!s.empty()) {
151  s.pop_back(); // delete last ':'
152  }
153  return s;
154 }
155 #endif // NDN_CXX_HAVE_TESTS
156 
157 #ifdef NDN_CXX_HAVE_TESTS
158 void
159 Logging::resetLevels()
160 {
161  this->setDefaultLevel(INITIAL_DEFAULT_LEVEL);
162  m_enabledLevel.clear();
163 }
164 #endif // NDN_CXX_HAVE_TESTS
165 
166 void
167 Logging::setDestination(std::ostream& os)
168 {
169  setDestination(shared_ptr<std::ostream>(&os, bind([]{})));
170 }
171 
172 void
173 Logging::setDestinationImpl(shared_ptr<std::ostream> os)
174 {
175  std::lock_guard<std::mutex> lock(m_mutex);
176 
177  m_destination = os;
178 
179  auto backend = boost::make_shared<boost::log::sinks::text_ostream_backend>();
180  backend->auto_flush(true);
181  backend->add_stream(boost::shared_ptr<std::ostream>(os.get(), bind([]{})));
182 
183  if (m_sink != nullptr) {
184  boost::log::core::get()->remove_sink(m_sink);
185  m_sink->flush();
186  m_sink.reset();
187  }
188 
189  m_sink = boost::make_shared<Sink>(backend);
190  m_sink->set_formatter(boost::log::expressions::stream << boost::log::expressions::message);
191  boost::log::core::get()->add_sink(m_sink);
192 }
193 
194 #ifdef NDN_CXX_HAVE_TESTS
195 shared_ptr<std::ostream>
196 Logging::getDestination()
197 {
198  return m_destination;
199 }
200 #endif // NDN_CXX_HAVE_TESTS
201 
202 void
203 Logging::flushImpl()
204 {
205  m_sink->flush();
206 }
207 
208 } // namespace util
209 } // namespace ndn
controls the logging facility
Definition: logging.hpp:46
Copyright (c) 2013-2016 Regents of the University of California.
Definition: common.hpp:74
static void setDestination(shared_ptr< std::ostream > os)
set log destination
Definition: logging.hpp:176
LogLevel
indicates the severity level of a log message
Definition: logger.hpp:40
LogLevel parseLogLevel(const std::string &s)
parse LogLevel from string
Definition: logger.cpp:60
static const LogLevel INITIAL_DEFAULT_LEVEL
Definition: logging.cpp:32