blob: 81623586487945732fef9f2e0213efba697b090b [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/*
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -04003 * Copyright (c) 2013-2019 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
Junxiao Shid1fc9a72018-12-12 16:35:34 +000025#include "ndn-cxx/detail/common.hpp"
Junxiao Shi7d054272016-08-04 17:00:41 +000026
Alexander Afanasyeved1e99d2016-11-05 09:59:35 -060027#ifdef HAVE_NDN_CXX_CUSTOM_LOGGER
Davide Pesavento7e780642018-11-24 15:51:34 -050028#include "ndn-cxx/util/custom-logging.hpp"
Alexander Afanasyeved1e99d2016-11-05 09:59:35 -060029#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
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -040083 /** \brief Set or replace log destination.
84 * \param destination log backend, e.g., returned by `makeDefaultStreamDestination`
Junxiao Shi7d054272016-08-04 17:00:41 +000085 *
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040086 * The initial destination is `std::clog`.
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -040087 *
88 * Note that if \p destination is nullptr, the destination will be removed and the
89 * application is expected to add its own. If the application does not set a custom
90 * destination (using this function or directly using Boost.Log routines), the default
91 * Boost.Log destination will be used. Refer to Boost.Log documentation and source code
92 * for details.
Junxiao Shi7d054272016-08-04 17:00:41 +000093 */
94 static void
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -040095 setDestination(boost::shared_ptr<boost::log::sinks::sink> destination);
Junxiao Shi7d054272016-08-04 17:00:41 +000096
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -040097 /** \brief Helper method to set stream log destination.
Davide Pesavento1c9c96c2018-04-25 10:45:08 -040098 * \param os a stream for log output; caller must ensure it remains valid
99 * until setDestination() is invoked again or program exits
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -0400100 *`
101 * This is equivalent to `setDestination(makeDefaultStreamDestination(shared_ptr<std::ostream>(&os, nullDeleter)))`.
Junxiao Shi7d054272016-08-04 17:00:41 +0000102 *
Junxiao Shi7d054272016-08-04 17:00:41 +0000103 */
104 static void
105 setDestination(std::ostream& os);
106
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400107 /** \brief Flush log backend.
Junxiao Shi7d054272016-08-04 17:00:41 +0000108 *
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400109 * This ensures all log messages are written to the destination stream.
Junxiao Shi7d054272016-08-04 17:00:41 +0000110 */
111 static void
112 flush();
113
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -0400114 /** \brief Create stream log destination using default formatting
115 */
116 static boost::shared_ptr<boost::log::sinks::sink>
117 makeDefaultStreamDestination(shared_ptr<std::ostream> os);
118
Junxiao Shi7d054272016-08-04 17:00:41 +0000119private:
120 Logging();
121
122 void
123 addLoggerImpl(Logger& logger);
124
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400125 void
126 registerLoggerNameImpl(std::string name);
127
Alexander Afanasyev354f3822017-03-27 15:26:41 -0500128 std::set<std::string>
dmcoomese062a182017-06-12 11:10:31 -0500129 getLoggerNamesImpl() const;
130
131 /**
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400132 * \brief Finds the appropriate LogLevel for a logger.
dmcoomese062a182017-06-12 11:10:31 -0500133 * \param moduleName name of logger
134 *
135 * This searches m_enabledLevel map to determine which LogLevel is appropriate for
136 * the incoming logger. It looks for the most specific prefix and broadens its
137 * prefix scope if a setting is not found. For example, when an incoming logger
138 * name is "ndn.a.b", it will search for "ndn.a.b" first. If this prefix is not
139 * contained in m_enabledLevel, it will search for "ndn.a.*", then "ndn.*", and
140 * finally "*". It defaults to INITIAL_DEFAULT_LEVEL if a matching prefix is not
141 * found.
142 */
143 LogLevel
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400144 findLevel(std::string moduleName) const;
Alexander Afanasyev354f3822017-03-27 15:26:41 -0500145
Junxiao Shi7d054272016-08-04 17:00:41 +0000146 void
dmcoomese062a182017-06-12 11:10:31 -0500147 setLevelImpl(const std::string& prefix, LogLevel level);
Junxiao Shi7d054272016-08-04 17:00:41 +0000148
149 void
150 setLevelImpl(const std::string& config);
151
152 void
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -0400153 setDestinationImpl(boost::shared_ptr<boost::log::sinks::sink> sink);
Junxiao Shi7d054272016-08-04 17:00:41 +0000154
155 void
156 flushImpl();
157
158NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
159 static Logging&
160 get();
161
162#ifdef NDN_CXX_HAVE_TESTS
163 bool
164 removeLogger(Logger& logger);
165
Junxiao Shi7d054272016-08-04 17:00:41 +0000166 void
167 resetLevels();
168
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -0400169 boost::shared_ptr<boost::log::sinks::sink>
dmcoomese062a182017-06-12 11:10:31 -0500170 getDestination() const;
171
172 void
173 setLevelImpl(const std::unordered_map<std::string, LogLevel>& prefixRules);
174
175 const std::unordered_map<std::string, LogLevel>&
176 getLevels() const;
Junxiao Shi7d054272016-08-04 17:00:41 +0000177#endif // NDN_CXX_HAVE_TESTS
178
179private:
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400180 friend Logger;
181
dmcoomese062a182017-06-12 11:10:31 -0500182 mutable std::mutex m_mutex;
183 std::unordered_map<std::string, LogLevel> m_enabledLevel; ///< module prefix => minimum level
Davide Pesavento1c9c96c2018-04-25 10:45:08 -0400184 std::unordered_multimap<std::string, Logger*> m_loggers; ///< module name => logger instance
Junxiao Shi7d054272016-08-04 17:00:41 +0000185
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -0400186 boost::shared_ptr<boost::log::sinks::sink> m_destination;
Junxiao Shi7d054272016-08-04 17:00:41 +0000187};
188
Alexander Afanasyev354f3822017-03-27 15:26:41 -0500189inline std::set<std::string>
190Logging::getLoggerNames()
191{
192 return get().getLoggerNamesImpl();
193}
194
Junxiao Shi7d054272016-08-04 17:00:41 +0000195inline void
dmcoomese062a182017-06-12 11:10:31 -0500196Logging::setLevel(const std::string& prefix, LogLevel level)
Junxiao Shi7d054272016-08-04 17:00:41 +0000197{
dmcoomese062a182017-06-12 11:10:31 -0500198 get().setLevelImpl(prefix, level);
Junxiao Shi7d054272016-08-04 17:00:41 +0000199}
200
201inline void
202Logging::setLevel(const std::string& config)
203{
204 get().setLevelImpl(config);
205}
206
207inline void
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -0400208Logging::setDestination(boost::shared_ptr<boost::log::sinks::sink> destination)
Junxiao Shi7d054272016-08-04 17:00:41 +0000209{
Alexander Afanasyev7b2f58c2019-07-13 11:50:19 -0400210 get().setDestinationImpl(std::move(destination));
Junxiao Shi7d054272016-08-04 17:00:41 +0000211}
212
213inline void
214Logging::flush()
215{
216 get().flushImpl();
217}
218
Junxiao Shi7d054272016-08-04 17:00:41 +0000219} // namespace util
220} // namespace ndn
221
Alexander Afanasyeved1e99d2016-11-05 09:59:35 -0600222#endif // HAVE_NDN_CXX_CUSTOM_LOGGER
223
Junxiao Shi7d054272016-08-04 17:00:41 +0000224#endif // NDN_UTIL_LOGGING_HPP