26 #include <boost/log/attributes/function.hpp> 27 #include <boost/log/expressions.hpp> 28 #include <boost/log/expressions/attr.hpp> 29 #include <boost/log/expressions/formatters/date_time.hpp> 30 #include <boost/log/support/date_time.hpp> 31 #include <boost/range/adaptor/map.hpp> 32 #include <boost/range/algorithm/copy.hpp> 33 #include <boost/range/iterator_range.hpp> 43 #pragma clang diagnostic ignored "-Wundefined-func-template" 55 const auto sinceEpoch = system_clock::now().time_since_epoch();
56 BOOST_ASSERT(sinceEpoch.count() >= 0);
58 const auto usecs =
std::abs(duration_cast<microseconds>(sinceEpoch).count());
59 const auto usecsPerSec = microseconds::period::den;
62 std::string buffer(10 + 1 + 6 + 1,
'\0');
63 BOOST_ASSERT_MSG(usecs / usecsPerSec <= 9999999999,
"whole seconds cannot fit in 10 characters");
65 static_assert(std::is_same<microseconds::rep, int_least64_t>::value,
66 "PRIdLEAST64 is incompatible with microseconds::rep");
68 ::snprintf(&buffer.front(), buffer.size(),
"%" PRIdLEAST64
".%06" PRIdLEAST64,
69 usecs / usecsPerSec, usecs % usecsPerSec);
76 BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp,
"Timestamp", std::string)
94 auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&std::clog, [] (
auto) {}));
95 this->setDestinationImpl(
std::move(destination));
97 const char* environ = std::getenv(
"NDN_LOG");
98 if (environ !=
nullptr) {
99 this->setLevelImpl(environ);
106 Logging::addLoggerImpl(
Logger& logger)
108 std::lock_guard<std::mutex> lock(m_mutex);
111 m_loggers.emplace(moduleName, &logger);
113 logger.
setLevel(findLevel(moduleName));
117 Logging::registerLoggerNameImpl(std::string name)
119 std::lock_guard<std::mutex> lock(m_mutex);
120 m_loggers.emplace(
std::move(name),
nullptr);
123 std::set<std::string>
124 Logging::getLoggerNamesImpl()
const 126 std::lock_guard<std::mutex> lock(m_mutex);
128 std::set<std::string> loggerNames;
129 boost::copy(m_loggers | boost::adaptors::map_keys, std::inserter(loggerNames, loggerNames.end()));
134 Logging::findLevel(std::string mn)
const 136 while (!mn.empty()) {
137 auto it = m_enabledLevel.find(mn);
138 if (it != m_enabledLevel.end()) {
141 size_t pos = mn.find_last_of(
'.');
142 if (pos < mn.size() - 1) {
143 mn = mn.substr(0, pos + 1);
145 else if (pos == mn.size() - 1) {
147 pos = mn.find_last_of(
'.');
148 if (pos != std::string::npos) {
149 mn = mn.substr(0, pos + 1);
160 auto it = m_enabledLevel.find(mn);
164 #ifdef NDN_CXX_HAVE_TESTS 166 Logging::removeLogger(
Logger& logger)
169 auto range = m_loggers.equal_range(moduleName);
170 for (
auto i = range.first; i != range.second; ++i) {
171 if (i->second == &logger) {
178 #endif // NDN_CXX_HAVE_TESTS 181 Logging::setLevelImpl(
const std::string& prefix,
LogLevel level)
183 std::lock_guard<std::mutex> lock(m_mutex);
185 if (prefix.empty() || prefix.back() ==
'*') {
186 std::string p = prefix;
191 for (
auto i = m_enabledLevel.begin(); i != m_enabledLevel.end();) {
192 if (i->first.compare(0, p.size(), p) == 0) {
193 i = m_enabledLevel.erase(i);
199 m_enabledLevel[p] = level;
201 for (
const auto& pair : m_loggers) {
202 if (pair.first.compare(0, p.size(), p) == 0 && pair.second !=
nullptr) {
203 pair.second->setLevel(level);
208 m_enabledLevel[prefix] = level;
209 auto range = boost::make_iterator_range(m_loggers.equal_range(prefix));
210 for (
const auto& pair : range) {
211 if (pair.second !=
nullptr) {
212 pair.second->setLevel(level);
219 Logging::setLevelImpl(
const std::string& config)
221 std::stringstream ss(config);
222 std::string configModule;
223 while (std::getline(ss, configModule,
':')) {
224 size_t ind = configModule.find(
'=');
225 if (ind == std::string::npos) {
226 NDN_THROW(std::invalid_argument(
"malformed logging config: '=' is missing"));
229 std::string moduleName = configModule.substr(0, ind);
231 this->setLevelImpl(moduleName, level);
235 #ifdef NDN_CXX_HAVE_TESTS 237 Logging::resetLevels()
239 this->setLevelImpl(
"*", INITIAL_DEFAULT_LEVEL);
240 m_enabledLevel.clear();
242 #endif // NDN_CXX_HAVE_TESTS 247 auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&os, [] (
auto) {}));
251 class TextOstreamBackend :
public boost::log::sinks::text_ostream_backend
254 TextOstreamBackend(std::shared_ptr<std::ostream> os)
258 add_stream(boost::shared_ptr<std::ostream>(m_stdPtr.get(), [] (
auto) {}));
264 std::shared_ptr<std::ostream> m_stdPtr;
267 boost::shared_ptr<boost::log::sinks::sink>
270 auto backend = boost::make_shared<TextOstreamBackend>(
std::move(os));
271 auto destination = boost::make_shared<boost::log::sinks::asynchronous_sink<TextOstreamBackend>>(backend);
273 namespace expr = boost::log::expressions;
274 destination->set_formatter(expr::stream
275 << expr::attr<std::string>(log::timestamp.get_name())
276 <<
" " << std::setw(5) << expr::attr<LogLevel>(log::severity.get_name()) <<
": " 277 <<
"[" << expr::attr<std::string>(log::module.get_name()) <<
"] " 283 Logging::setDestinationImpl(boost::shared_ptr<boost::log::sinks::sink> destination)
285 std::lock_guard<std::mutex> lock(m_mutex);
287 if (destination == m_destination) {
291 if (m_destination !=
nullptr) {
293 m_destination->flush();
298 if (m_destination !=
nullptr) {
303 #ifdef NDN_CXX_HAVE_TESTS 304 boost::shared_ptr<boost::log::sinks::sink>
305 Logging::getDestination()
const 307 return m_destination;
311 Logging::setLevelImpl(
const std::unordered_map<std::string, LogLevel>& prefixRules)
314 for (
const auto& rule : prefixRules) {
315 setLevelImpl(rule.first, rule.second);
319 const std::unordered_map<std::string, LogLevel>&
320 Logging::getLevels()
const 322 return m_enabledLevel;
324 #endif // NDN_CXX_HAVE_TESTS 329 std::lock_guard<std::mutex> lock(m_mutex);
331 if (m_destination !=
nullptr) {
332 m_destination->flush();
Controls the logging facility.
constexpr duration< Rep, Period > abs(duration< Rep, Period > d)
LogLevel
Indicates the severity level of a log message.
R & get(variant< T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 > &v, nonstd::in_place_t(&)(nonstd::detail::in_place_type_tag< R >)=nonstd::in_place_type< R >)
static std::string makeTimestamp()
LogLevel parseLogLevel(const std::string &s)
Parse LogLevel from a string.
static boost::shared_ptr< boost::log::sinks::sink > makeDefaultStreamDestination(shared_ptr< std::ostream > os)
Create stream log destination using default formatting.
static const LogLevel INITIAL_DEFAULT_LEVEL
const std::string & getModuleName() const
Represents a log module in the logging facility.
static void setDestination(boost::shared_ptr< boost::log::sinks::sink > destination)
Set or replace log destination.
void setLevel(LogLevel level)