blob: 9961598df5bf6aeb95baf197054d7ea970a96b24 [file] [log] [blame]
Junxiao Shi7d054272016-08-04 17:00:41 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventocdcde902017-08-23 15:40:22 -04002/*
Alexander Afanasyev354f3822017-03-27 15:26:41 -05003 * Copyright (c) 2013-2017 Regents of the University of California.
Junxiao Shi7d054272016-08-04 17:00:41 +00004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "logging.hpp"
23#include "logger.hpp"
24
25#include <boost/log/expressions.hpp>
Alexander Afanasyev354f3822017-03-27 15:26:41 -050026#include <boost/range/adaptor/map.hpp>
Davide Pesaventocdcde902017-08-23 15:40:22 -040027#include <boost/range/algorithm/copy.hpp>
28
Junxiao Shi7d054272016-08-04 17:00:41 +000029#include <cstdlib>
Davide Pesaventocdcde902017-08-23 15:40:22 -040030#include <iostream>
31#include <sstream>
Junxiao Shi7d054272016-08-04 17:00:41 +000032
33namespace ndn {
34namespace util {
35
36static const LogLevel INITIAL_DEFAULT_LEVEL = LogLevel::NONE;
37
38Logging&
39Logging::get()
40{
41 // Initialization of block-scope variables with static storage duration is thread-safe.
42 // See ISO C++ standard [stmt.dcl]/4
43 static Logging instance;
44 return instance;
45}
46
47Logging::Logging()
48{
49 this->setDestinationImpl(shared_ptr<std::ostream>(&std::clog, bind([]{})));
50
Junxiao Shi1fe7ce52016-08-08 05:48:02 +000051 const char* environ = std::getenv("NDN_LOG");
Junxiao Shi7d054272016-08-04 17:00:41 +000052 if (environ != nullptr) {
53 this->setLevelImpl(environ);
54 }
55}
56
57void
58Logging::addLoggerImpl(Logger& logger)
59{
60 std::lock_guard<std::mutex> lock(m_mutex);
61
62 const std::string& moduleName = logger.getModuleName();
63 m_loggers.insert({moduleName, &logger});
64
65 auto levelIt = m_enabledLevel.find(moduleName);
66 if (levelIt == m_enabledLevel.end()) {
67 levelIt = m_enabledLevel.find("*");
68 }
69 LogLevel level = levelIt == m_enabledLevel.end() ? INITIAL_DEFAULT_LEVEL : levelIt->second;
70 logger.setLevel(level);
71}
72
Alexander Afanasyev354f3822017-03-27 15:26:41 -050073std::set<std::string>
74Logging::getLoggerNamesImpl()
75{
76 std::lock_guard<std::mutex> lock(m_mutex);
77
78 std::set<std::string> loggerNames;
79 boost::copy(m_loggers | boost::adaptors::map_keys, std::inserter(loggerNames, loggerNames.end()));
80 return loggerNames;
81}
82
Junxiao Shi7d054272016-08-04 17:00:41 +000083#ifdef NDN_CXX_HAVE_TESTS
84bool
85Logging::removeLogger(Logger& logger)
86{
87 const std::string& moduleName = logger.getModuleName();
88 auto range = m_loggers.equal_range(moduleName);
89 for (auto i = range.first; i != range.second; ++i) {
90 if (i->second == &logger) {
91 m_loggers.erase(i);
92 return true;
93 }
94 }
95 return false;
96}
97#endif // NDN_CXX_HAVE_TESTS
98
99void
100Logging::setLevelImpl(const std::string& moduleName, LogLevel level)
101{
102 std::lock_guard<std::mutex> lock(m_mutex);
103
104 if (moduleName == "*") {
105 this->setDefaultLevel(level);
106 return;
107 }
108
109 m_enabledLevel[moduleName] = level;
110 auto range = m_loggers.equal_range(moduleName);
111 for (auto i = range.first; i != range.second; ++i) {
112 i->second->setLevel(level);
113 }
114}
115
116void
117Logging::setDefaultLevel(LogLevel level)
118{
119 m_enabledLevel.clear();
120 m_enabledLevel["*"] = level;
121
122 for (auto i = m_loggers.begin(); i != m_loggers.end(); ++i) {
123 i->second->setLevel(level);
124 }
125}
126
127void
128Logging::setLevelImpl(const std::string& config)
129{
130 std::stringstream ss(config);
131 std::string configModule;
132 while (std::getline(ss, configModule, ':')) {
133 size_t ind = configModule.find('=');
134 if (ind == std::string::npos) {
135 BOOST_THROW_EXCEPTION(std::invalid_argument("malformed logging config: '=' is missing"));
136 }
137
138 std::string moduleName = configModule.substr(0, ind);
139 LogLevel level = parseLogLevel(configModule.substr(ind+1));
140
141 this->setLevelImpl(moduleName, level);
142 }
143}
144
145#ifdef NDN_CXX_HAVE_TESTS
146std::string
147Logging::getLevels() const
148{
149 std::ostringstream os;
150
151 auto defaultLevelIt = m_enabledLevel.find("*");
152 if (defaultLevelIt != m_enabledLevel.end()) {
153 os << "*=" << defaultLevelIt->second << ':';
154 }
155
156 for (auto it = m_enabledLevel.begin(); it != m_enabledLevel.end(); ++it) {
157 if (it->first == "*") {
158 continue;
159 }
160 os << it->first << '=' << it->second << ':';
161 }
162
163 std::string s = os.str();
164 if (!s.empty()) {
165 s.pop_back(); // delete last ':'
166 }
167 return s;
168}
169#endif // NDN_CXX_HAVE_TESTS
170
171#ifdef NDN_CXX_HAVE_TESTS
172void
173Logging::resetLevels()
174{
175 this->setDefaultLevel(INITIAL_DEFAULT_LEVEL);
176 m_enabledLevel.clear();
177}
178#endif // NDN_CXX_HAVE_TESTS
179
180void
181Logging::setDestination(std::ostream& os)
182{
183 setDestination(shared_ptr<std::ostream>(&os, bind([]{})));
184}
185
186void
187Logging::setDestinationImpl(shared_ptr<std::ostream> os)
188{
189 std::lock_guard<std::mutex> lock(m_mutex);
190
191 m_destination = os;
192
193 auto backend = boost::make_shared<boost::log::sinks::text_ostream_backend>();
194 backend->auto_flush(true);
195 backend->add_stream(boost::shared_ptr<std::ostream>(os.get(), bind([]{})));
196
197 if (m_sink != nullptr) {
198 boost::log::core::get()->remove_sink(m_sink);
199 m_sink->flush();
200 m_sink.reset();
201 }
202
203 m_sink = boost::make_shared<Sink>(backend);
204 m_sink->set_formatter(boost::log::expressions::stream << boost::log::expressions::message);
205 boost::log::core::get()->add_sink(m_sink);
206}
207
208#ifdef NDN_CXX_HAVE_TESTS
209shared_ptr<std::ostream>
210Logging::getDestination()
211{
212 return m_destination;
213}
214#endif // NDN_CXX_HAVE_TESTS
215
216void
217Logging::flushImpl()
218{
219 m_sink->flush();
220}
221
222} // namespace util
223} // namespace ndn