blob: 8fc634204b926c39834601c2a1107f75ee8cdf58 [file] [log] [blame]
Junxiao Shi7d054272016-08-04 17:00:41 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
dmcoomese062a182017-06-12 11:10:31 -05002/*
Davide Pesavento1c9c96c2018-04-25 10:45:08 -04003 * Copyright (c) 2013-2018 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#ifndef NDN_UTIL_LOGGING_HPP
23#define NDN_UTIL_LOGGING_HPP
24
25#include "../common.hpp"
26
Alexander Afanasyeved1e99d2016-11-05 09:59:35 -060027#ifdef HAVE_NDN_CXX_CUSTOM_LOGGER
28#include "ndn-cxx-custom-logging.hpp"
29#else
30
Junxiao Shi7d054272016-08-04 17:00:41 +000031#include <boost/log/sinks.hpp>
32#include <mutex>
33#include <unordered_map>
34
35namespace ndn {
36namespace util {
37
38enum class LogLevel;
39class Logger;
40
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040041/** \brief Controls the logging facility.
Junxiao Shi7d054272016-08-04 17:00:41 +000042 *
43 * \note Public static methods are thread safe.
44 * Non-public methods are not guaranteed to be thread safe.
45 */
46class Logging : noncopyable
47{
48public:
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040049 /** \brief Get list of all registered logger names.
Alexander Afanasyev354f3822017-03-27 15:26:41 -050050 */
51 static std::set<std::string>
52 getLoggerNames();
53
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040054 /** \brief Set severity level.
55 * \param prefix logger prefix; this can be a specific logger name, a general prefix like
56 * `"ndn.a.*"` to apply a setting for all modules that contain that prefix,
57 * or `"*"` for all modules
Junxiao Shi7d054272016-08-04 17:00:41 +000058 * \param level minimum severity level
59 *
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040060 * Log messages are output only if their severity is greater than the current minimum severity
61 * level. The initial severity level is \c LogLevel::NONE, which enables FATAL messages only.
Junxiao Shi7d054272016-08-04 17:00:41 +000062 */
63 static void
dmcoomese062a182017-06-12 11:10:31 -050064 setLevel(const std::string& prefix, LogLevel level);
Junxiao Shi7d054272016-08-04 17:00:41 +000065
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040066 /** \brief Set severity levels with a config string.
67 * \param config colon-separated `key=value` pairs
Junxiao Shi7d054272016-08-04 17:00:41 +000068 * \throw std::invalid_argument config string is malformed
69 *
70 * \code
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040071 * Logging::setLevel("*=INFO:Face=DEBUG:NfdController=WARN");
Junxiao Shi7d054272016-08-04 17:00:41 +000072 * \endcode
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040073 * is equivalent to:
Junxiao Shi7d054272016-08-04 17:00:41 +000074 * \code
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040075 * Logging::setLevel("*", LogLevel::INFO);
76 * Logging::setLevel("Face", LogLevel::DEBUG);
77 * Logging::setLevel("NfdController", LogLevel::WARN);
Junxiao Shi7d054272016-08-04 17:00:41 +000078 * \endcode
79 */
80 static void
81 setLevel(const std::string& config);
82
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040083 /** \brief Set log destination.
Junxiao Shi7d054272016-08-04 17:00:41 +000084 * \param os a stream for log output
85 *
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040086 * The initial destination is `std::clog`.
Junxiao Shi7d054272016-08-04 17:00:41 +000087 */
88 static void
89 setDestination(shared_ptr<std::ostream> os);
90
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040091 /** \brief Set log destination.
92 * \param os a stream for log output; caller must ensure it remains valid
93 * until setDestination() is invoked again or program exits
Junxiao Shi7d054272016-08-04 17:00:41 +000094 *
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040095 * This is equivalent to `setDestination(shared_ptr<std::ostream>(&os, nullDeleter))`.
Junxiao Shi7d054272016-08-04 17:00:41 +000096 */
97 static void
98 setDestination(std::ostream& os);
99
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400100 /** \brief Flush log backend.
Junxiao Shi7d054272016-08-04 17:00:41 +0000101 *
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400102 * This ensures all log messages are written to the destination stream.
Junxiao Shi7d054272016-08-04 17:00:41 +0000103 */
104 static void
105 flush();
106
107private:
108 Logging();
109
110 void
111 addLoggerImpl(Logger& logger);
112
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400113 void
114 registerLoggerNameImpl(std::string name);
115
Alexander Afanasyev354f3822017-03-27 15:26:41 -0500116 std::set<std::string>
dmcoomese062a182017-06-12 11:10:31 -0500117 getLoggerNamesImpl() const;
118
119 /**
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400120 * \brief Finds the appropriate LogLevel for a logger.
dmcoomese062a182017-06-12 11:10:31 -0500121 * \param moduleName name of logger
122 *
123 * This searches m_enabledLevel map to determine which LogLevel is appropriate for
124 * the incoming logger. It looks for the most specific prefix and broadens its
125 * prefix scope if a setting is not found. For example, when an incoming logger
126 * name is "ndn.a.b", it will search for "ndn.a.b" first. If this prefix is not
127 * contained in m_enabledLevel, it will search for "ndn.a.*", then "ndn.*", and
128 * finally "*". It defaults to INITIAL_DEFAULT_LEVEL if a matching prefix is not
129 * found.
130 */
131 LogLevel
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400132 findLevel(std::string moduleName) const;
Alexander Afanasyev354f3822017-03-27 15:26:41 -0500133
Junxiao Shi7d054272016-08-04 17:00:41 +0000134 void
dmcoomese062a182017-06-12 11:10:31 -0500135 setLevelImpl(const std::string& prefix, LogLevel level);
Junxiao Shi7d054272016-08-04 17:00:41 +0000136
137 void
138 setLevelImpl(const std::string& config);
139
140 void
141 setDestinationImpl(shared_ptr<std::ostream> os);
142
143 void
144 flushImpl();
145
146NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
147 static Logging&
148 get();
149
150#ifdef NDN_CXX_HAVE_TESTS
151 bool
152 removeLogger(Logger& logger);
153
Junxiao Shi7d054272016-08-04 17:00:41 +0000154 void
155 resetLevels();
156
157 shared_ptr<std::ostream>
dmcoomese062a182017-06-12 11:10:31 -0500158 getDestination() const;
159
160 void
161 setLevelImpl(const std::unordered_map<std::string, LogLevel>& prefixRules);
162
163 const std::unordered_map<std::string, LogLevel>&
164 getLevels() const;
Junxiao Shi7d054272016-08-04 17:00:41 +0000165#endif // NDN_CXX_HAVE_TESTS
166
167private:
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400168 friend Logger;
169
dmcoomese062a182017-06-12 11:10:31 -0500170 mutable std::mutex m_mutex;
171 std::unordered_map<std::string, LogLevel> m_enabledLevel; ///< module prefix => minimum level
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400172 std::unordered_multimap<std::string, Logger*> m_loggers; ///< module name => logger instance
Junxiao Shi7d054272016-08-04 17:00:41 +0000173
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400174 using Sink = boost::log::sinks::asynchronous_sink<boost::log::sinks::text_ostream_backend>;
Junxiao Shi7d054272016-08-04 17:00:41 +0000175 boost::shared_ptr<Sink> m_sink;
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400176 shared_ptr<std::ostream> m_destination;
Junxiao Shi7d054272016-08-04 17:00:41 +0000177};
178
Alexander Afanasyev354f3822017-03-27 15:26:41 -0500179inline std::set<std::string>
180Logging::getLoggerNames()
181{
182 return get().getLoggerNamesImpl();
183}
184
Junxiao Shi7d054272016-08-04 17:00:41 +0000185inline void
dmcoomese062a182017-06-12 11:10:31 -0500186Logging::setLevel(const std::string& prefix, LogLevel level)
Junxiao Shi7d054272016-08-04 17:00:41 +0000187{
dmcoomese062a182017-06-12 11:10:31 -0500188 get().setLevelImpl(prefix, level);
Junxiao Shi7d054272016-08-04 17:00:41 +0000189}
190
191inline void
192Logging::setLevel(const std::string& config)
193{
194 get().setLevelImpl(config);
195}
196
197inline void
198Logging::setDestination(shared_ptr<std::ostream> os)
199{
dmcoomese062a182017-06-12 11:10:31 -0500200 get().setDestinationImpl(std::move(os));
Junxiao Shi7d054272016-08-04 17:00:41 +0000201}
202
203inline void
204Logging::flush()
205{
206 get().flushImpl();
207}
208
Junxiao Shi7d054272016-08-04 17:00:41 +0000209} // namespace util
210} // namespace ndn
211
Alexander Afanasyeved1e99d2016-11-05 09:59:35 -0600212#endif // HAVE_NDN_CXX_CUSTOM_LOGGER
213
Junxiao Shi7d054272016-08-04 17:00:41 +0000214#endif // NDN_UTIL_LOGGING_HPP