27 #include "ndn-cxx/util/impl/logger-android.hpp"
30 #include <boost/log/attributes/function.hpp>
31 #include <boost/log/expressions.hpp>
32 #include <boost/log/expressions/attr.hpp>
33 #include <boost/log/expressions/formatters/date_time.hpp>
34 #include <boost/log/support/date_time.hpp>
35 #include <boost/range/adaptor/map.hpp>
36 #include <boost/range/algorithm/copy.hpp>
37 #include <boost/range/iterator_range.hpp>
53 const auto sinceEpoch = system_clock::now().time_since_epoch();
54 BOOST_ASSERT(sinceEpoch.count() >= 0);
56 const auto usecs =
std::abs(duration_cast<microseconds>(sinceEpoch).count());
57 const auto usecsPerSec = microseconds::period::den;
60 std::string buffer(10 + 1 + 6 + 1,
'\0');
61 BOOST_ASSERT_MSG(usecs / usecsPerSec <= 9999999999,
"whole seconds cannot fit in 10 characters");
63 static_assert(std::is_same_v<microseconds::rep, int_least64_t>,
64 "PRIdLEAST64 is incompatible with microseconds::rep");
65 std::snprintf(&buffer.front(), buffer.size(),
"%" PRIdLEAST64
".%06" PRIdLEAST64,
66 usecs / usecsPerSec, usecs % usecsPerSec);
73 BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp,
"Timestamp", std::string)
91 bool wantAutoFlush = std::getenv(
"NDN_LOG_NOFLUSH") ==
nullptr;
92 auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&std::clog, [] (
auto&&) {}),
95 auto destination = detail::makeAndroidLogger();
99 this->setDestinationImpl(std::move(destination));
101 const char* env = std::getenv(
"NDN_LOG");
102 if (env !=
nullptr) {
103 this->setLevelImpl(env);
106 boost::log::core::get()->add_global_attribute(
"Timestamp",
107 boost::log::attributes::make_function(&log::makeTimestamp));
111 Logging::addLoggerImpl(Logger& logger)
113 std::lock_guard<std::mutex> lock(m_mutex);
115 const std::string& moduleName = logger.getModuleName();
116 m_loggers.emplace(moduleName, &logger);
118 logger.setLevel(findLevel(moduleName));
122 Logging::registerLoggerNameImpl(std::string name)
124 std::lock_guard<std::mutex> lock(m_mutex);
125 m_loggers.emplace(std::move(name),
nullptr);
128 std::set<std::string>
129 Logging::getLoggerNamesImpl()
const
131 std::lock_guard<std::mutex> lock(m_mutex);
133 std::set<std::string> loggerNames;
134 boost::copy(m_loggers | boost::adaptors::map_keys, std::inserter(loggerNames, loggerNames.end()));
139 Logging::findLevel(std::string mn)
const
141 while (!mn.empty()) {
142 if (
auto it = m_enabledLevel.find(mn); it != m_enabledLevel.end()) {
145 size_t pos = mn.find_last_of(
'.');
146 if (pos < mn.size() - 1) {
147 mn = mn.substr(0, pos + 1);
149 else if (pos == mn.size() - 1) {
151 pos = mn.find_last_of(
'.');
152 if (pos != std::string::npos) {
153 mn = mn.substr(0, pos + 1);
164 auto it = m_enabledLevel.find(mn);
168 #ifdef NDN_CXX_WITH_TESTS
170 Logging::removeLogger(Logger& logger)
172 const std::string& moduleName = logger.getModuleName();
173 auto range = m_loggers.equal_range(moduleName);
174 for (
auto i = range.first; i != range.second; ++i) {
175 if (i->second == &logger) {
185 Logging::setLevelImpl(
const std::string& prefix,
LogLevel level)
187 std::lock_guard<std::mutex> lock(m_mutex);
189 if (prefix.empty() || prefix.back() ==
'*') {
190 std::string p = prefix;
195 for (
auto i = m_enabledLevel.begin(); i != m_enabledLevel.end();) {
196 if (i->first.compare(0, p.size(), p) == 0) {
197 i = m_enabledLevel.erase(i);
203 m_enabledLevel[p] = level;
205 for (
const auto& pair : m_loggers) {
206 if (pair.first.compare(0, p.size(), p) == 0 && pair.second !=
nullptr) {
207 pair.second->setLevel(level);
212 m_enabledLevel[prefix] = level;
213 auto range = boost::make_iterator_range(m_loggers.equal_range(prefix));
214 for (
const auto& pair : range) {
215 if (pair.second !=
nullptr) {
216 pair.second->setLevel(level);
223 Logging::setLevelImpl(
const std::string& config)
225 std::stringstream ss(config);
226 std::string configModule;
227 while (std::getline(ss, configModule,
':')) {
228 size_t ind = configModule.find(
'=');
229 if (ind == std::string::npos) {
230 NDN_THROW(std::invalid_argument(
"malformed logging config: '=' is missing"));
233 std::string moduleName = configModule.substr(0, ind);
235 this->setLevelImpl(moduleName, level);
239 #ifdef NDN_CXX_WITH_TESTS
241 Logging::resetLevels()
244 m_enabledLevel.clear();
251 auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&os, [] (
auto&&) {}),
253 setDestination(std::move(destination));
256 class TextOstreamBackend :
public boost::log::sinks::text_ostream_backend
259 TextOstreamBackend(std::shared_ptr<std::ostream> os,
bool wantAutoFlush)
260 : m_stdPtr(std::move(os))
262 auto_flush(wantAutoFlush);
263 add_stream(boost::shared_ptr<std::ostream>(m_stdPtr.get(), [] (
auto&&) {}));
269 std::shared_ptr<std::ostream> m_stdPtr;
272 boost::shared_ptr<boost::log::sinks::sink>
275 auto backend = boost::make_shared<TextOstreamBackend>(std::move(os), wantAutoFlush);
276 auto destination = boost::make_shared<boost::log::sinks::asynchronous_sink<TextOstreamBackend>>(backend);
278 namespace expr = boost::log::expressions;
279 destination->set_formatter(expr::stream
280 << expr::attr<std::string>(log::timestamp.get_name())
281 <<
" " << std::setw(5) << expr::attr<LogLevel>(log::severity.get_name()) <<
": "
282 <<
"[" << expr::attr<std::string>(log::module.get_name()) <<
"] "
288 Logging::setDestinationImpl(boost::shared_ptr<boost::log::sinks::sink> destination)
290 std::lock_guard<std::mutex> lock(m_mutex);
292 if (destination == m_destination) {
296 if (m_destination !=
nullptr) {
297 boost::log::core::get()->remove_sink(m_destination);
298 m_destination->flush();
301 m_destination = std::move(destination);
303 if (m_destination !=
nullptr) {
304 boost::log::core::get()->add_sink(m_destination);
308 #ifdef NDN_CXX_WITH_TESTS
309 boost::shared_ptr<boost::log::sinks::sink>
310 Logging::getDestination()
const
312 return m_destination;
316 Logging::setLevelImpl(
const std::unordered_map<std::string, LogLevel>& prefixRules)
319 for (
const auto& rule : prefixRules) {
320 setLevelImpl(rule.first, rule.second);
324 const std::unordered_map<std::string, LogLevel>&
325 Logging::getLevels()
const
327 return m_enabledLevel;
334 std::lock_guard<std::mutex> lock(m_mutex);
336 if (m_destination !=
nullptr) {
337 m_destination->flush();
Controls the logging facility.
static void setDestination(boost::shared_ptr< boost::log::sinks::sink > destination)
Set or replace log destination.
static boost::shared_ptr< boost::log::sinks::sink > makeDefaultStreamDestination(shared_ptr< std::ostream > os, bool wantAutoFlush=true)
Create stream log destination using default formatting.
constexpr duration< Rep, Period > abs(duration< Rep, Period > d)
Returns the absolute value of the duration d.
LogLevel parseLogLevel(std::string_view s)
Parse LogLevel from a string.
constexpr LogLevel INITIAL_DEFAULT_LEVEL
LogLevel
Indicates the severity level of a log message.