blob: aae7795ea122e446f11b5756816a498ec2a71733 [file] [log] [blame]
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Yumin Xiaab497452016-05-10 20:23:24 +08003 * Copyright (c) 2014-2016, Regents of the University of California,
Alexander Afanasyev8269a052015-02-09 16:25:36 -08004 * 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.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
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/>.
Alexander Afanasyev8269a052015-02-09 16:25:36 -080024 */
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060025
26#include "logger-factory.hpp"
27
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -080028#include <boost/range/adaptor/map.hpp>
Yumin Xiaab497452016-05-10 20:23:24 +080029#include <boost/log/core.hpp>
30#include <boost/log/expressions.hpp>
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -080031
Alexander Afanasyev8269a052015-02-09 16:25:36 -080032#ifdef HAVE_CUSTOM_LOGGER
33#error "This file should not be compiled when custom logger is used"
34#endif
35
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060036namespace nfd {
37
Steve DiBenedetto6ad48ca2014-04-22 09:39:31 -060038NFD_LOG_INIT("LoggerFactory");
39
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060040LoggerFactory&
41LoggerFactory::getInstance()
42{
43 static LoggerFactory globalLoggerFactory;
44
45 return globalLoggerFactory;
46}
47
48LoggerFactory::LoggerFactory()
49 : m_defaultLevel(LOG_INFO)
50{
51 m_levelNames["NONE"] = LOG_NONE;
52 m_levelNames["ERROR"] = LOG_ERROR;
53 m_levelNames["WARN"] = LOG_WARN;
54 m_levelNames["INFO"] = LOG_INFO;
55 m_levelNames["DEBUG"] = LOG_DEBUG;
56 m_levelNames["TRACE"] = LOG_TRACE;
57 m_levelNames["ALL"] = LOG_ALL;
Yumin Xiaab497452016-05-10 20:23:24 +080058
59 auto backend = boost::make_shared<boost::log::sinks::text_ostream_backend>();
60 backend->auto_flush(true);
61 backend->add_stream(boost::shared_ptr<std::ostream>(&std::clog, bind([]{})));
62
63 m_sink = boost::make_shared<Sink>(backend);
64 m_sink->set_formatter(boost::log::expressions::stream << boost::log::expressions::message);
65 boost::log::core::get()->add_sink(m_sink);
66}
67
68LoggerFactory::~LoggerFactory()
69{
70 boost::log::core::get()->remove_sink(m_sink);
71 m_sink->stop();
72 m_sink->flush();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060073}
74
75void
76LoggerFactory::setConfigFile(ConfigFile& config)
77{
78 config.addSectionHandler("log", bind(&LoggerFactory::onConfig, this, _1, _2, _3));
79}
80
81LogLevel
82LoggerFactory::parseLevel(const std::string& level)
83{
84 std::string upperLevel = level;
85 boost::to_upper(upperLevel);
86
87 // std::cerr << "parsing level: " << upperLevel << std::endl;;
88 // std::cerr << "# levels: " << m_levelNames.size() << std::endl;
89 // std::cerr << m_levelNames.begin()->first << std::endl;
90
91 LevelMap::const_iterator levelIt = m_levelNames.find(upperLevel);
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -080092 if (levelIt != m_levelNames.end()) {
93 return levelIt->second;
94 }
95 try {
96 uint32_t levelNo = boost::lexical_cast<uint32_t>(level);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060097
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -080098 if ((boost::lexical_cast<uint32_t>(LOG_NONE) <= levelNo &&
99 levelNo <= boost::lexical_cast<uint32_t>(LOG_TRACE)) ||
100 levelNo == LOG_ALL) {
101 return static_cast<LogLevel>(levelNo);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600102 }
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800103 }
104 catch (const boost::bad_lexical_cast& error) {
105 }
106
Spyridon Mastorakis149e02c2015-07-27 13:22:22 -0700107 BOOST_THROW_EXCEPTION(LoggerFactory::Error("Unsupported logging level \"" + level + "\""));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600108}
109
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300110LogLevel
111LoggerFactory::extractLevel(const ConfigSection& item, const std::string& key)
112{
113 std::string levelString;
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800114 try {
115 levelString = item.get_value<std::string>();
116 }
117 catch (const boost::property_tree::ptree_error& error) {
118 }
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300119
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800120 if (levelString.empty()) {
Spyridon Mastorakis149e02c2015-07-27 13:22:22 -0700121 BOOST_THROW_EXCEPTION(LoggerFactory::Error("No logging level found for option \"" + key + "\""));
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800122 }
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300123
124 return parseLevel(levelString);
125}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600126
127void
128LoggerFactory::onConfig(const ConfigSection& section,
129 bool isDryRun,
130 const std::string& filename)
131{
132// log
133// {
134// ; default_level specifies the logging level for modules
135// ; that are not explicitly named. All debugging levels
136// ; listed above the selected value are enabled.
137//
138// default_level INFO
139//
140// ; You may also override the default for specific modules:
141//
142// FibManager DEBUG
143// Forwarder WARN
144// }
145
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800146 if (!isDryRun) {
147 ConfigSection::const_assoc_iterator item = section.find("default_level");
148 if (item != section.not_found()) {
149 LogLevel level = extractLevel(item->second, "default_level");
150 setDefaultLevel(level);
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300151 }
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800152 else {
153 setDefaultLevel(LOG_INFO);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600154 }
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800155 }
156
157 for (const auto& i : section) {
158 LogLevel level = extractLevel(i.second, i.first);
159
160 if (i.first == "default_level") {
161 // do nothing
162 }
163 else {
164 std::unique_lock<std::mutex> lock(m_loggersGuard);
165 LoggerMap::iterator loggerIt = m_loggers.find(i.first);
166 if (loggerIt == m_loggers.end()) {
167 lock.unlock();
168 NFD_LOG_DEBUG("Failed to configure logging level for module \"" <<
169 i.first << "\" (module not found)");
170 }
171 else if (!isDryRun) {
172 loggerIt->second.setLogLevel(level);
173 lock.unlock();
174 NFD_LOG_DEBUG("Changing level for module " << i.first << " to " << level);
175 }
176 }
177 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600178}
179
180void
181LoggerFactory::setDefaultLevel(LogLevel level)
182{
183 // std::cerr << "changing to default_level " << level << std::endl;
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800184 std::lock_guard<std::mutex> lock(m_loggersGuard);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600185
186 m_defaultLevel = level;
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800187 for (auto&& logger : m_loggers) {
188 // std::cerr << "changing " << i->first << " to default " << m_defaultLevel << std::endl;
189 logger.second.setLogLevel(m_defaultLevel);
190 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600191}
192
Yumin Xiaab497452016-05-10 20:23:24 +0800193void
194LoggerFactory::flushBackend()
195{
196 m_sink->flush();
197}
198
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600199Logger&
200LoggerFactory::create(const std::string& moduleName)
201{
202 return LoggerFactory::getInstance().createLogger(moduleName);
203}
204
205Logger&
206LoggerFactory::createLogger(const std::string& moduleName)
207{
208 // std::cerr << "creating logger for " << moduleName
209 // << " with level " << m_defaultLevel << std::endl;
210
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800211 std::lock_guard<std::mutex> lock(m_loggersGuard);
212
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600213 std::pair<LoggerMap::iterator, bool> loggerIt =
214 m_loggers.insert(NameAndLogger(moduleName, Logger(moduleName, m_defaultLevel)));
215
216 return loggerIt.first->second;
217}
218
219std::list<std::string>
220LoggerFactory::getModules() const
221{
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800222 std::lock_guard<std::mutex> lock(m_loggersGuard);
223
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600224 std::list<std::string> modules;
Alexander Afanasyev6b34ab92015-02-11 21:22:46 -0800225 for (const auto& loggerName : m_loggers | boost::adaptors::map_keys) {
226 modules.push_back(loggerName);
227 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600228
229 return modules;
230}
231
232} // namespace nfd