Log.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima).
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. #ifndef _FASTDDS_LOG_LOG_HPP_
  16. #define _FASTDDS_LOG_LOG_HPP_
  17. #include <fastrtps/utils/DBQueue.h>
  18. #include <fastrtps/fastrtps_dll.h>
  19. #include <thread>
  20. #include <sstream>
  21. #include <atomic>
  22. #include <regex>
  23. /**
  24. * eProsima log layer. Logging categories and verbosities can be specified dynamically at runtime. However, even on a category
  25. * not covered by the current verbosity level, there is some overhead on calling a log macro. For maximum performance, you can
  26. * opt out of logging any particular level by defining the following symbols:
  27. *
  28. * * define LOG_NO_ERROR
  29. * * define LOG_NO_WARNING
  30. * * define LOG_NO_INFO
  31. *
  32. * Additionally. the lowest level (Info) is disabled by default on release branches.
  33. */
  34. // Logging API:
  35. //! Logs an info message. Disable it through Log::SetVerbosity, define LOG_NO_INFO, or being in a release branch
  36. #define logInfo(cat, msg) logInfo_(cat, msg)
  37. //! Logs a warning. Disable reporting through Log::SetVerbosity or define LOG_NO_WARNING
  38. #define logWarning(cat, msg) logWarning_(cat, msg)
  39. //! Logs an error. Disable reporting through define LOG_NO_ERROR
  40. #define logError(cat, msg) logError_(cat, msg)
  41. namespace eprosima {
  42. namespace fastdds {
  43. namespace dds {
  44. class LogConsumer;
  45. /**
  46. * Logging utilities.
  47. * Logging is accessed through the three macros above, and configuration on the log output
  48. * can be achieved through static methods on the class. Logging at various levels can be
  49. * disabled dynamically (through the Verbosity level) or statically (through the LOG_NO_[VERB]
  50. * macros) for maximum performance.
  51. * @ingroup COMMON_MODULE
  52. */
  53. class Log
  54. {
  55. public:
  56. /**
  57. * Types of log entry.
  58. * * Error: Maximum priority. Can only be disabled statically through LOG_NO_ERROR.
  59. * * Warning: Medium priority. Can be disabled statically and dynamically.
  60. * * Info: Low priority. Useful for debugging. Disabled by default on release branches.
  61. */
  62. enum Kind
  63. {
  64. Error,
  65. Warning,
  66. Info,
  67. };
  68. /**
  69. * Registers an user defined consumer to route log output.
  70. * There is a default stdout consumer active as default.
  71. * @param consumer r-value to a consumer unique_ptr. It will be invalidated after the call.
  72. */
  73. RTPS_DllAPI static void RegisterConsumer(
  74. std::unique_ptr<LogConsumer>&& consumer);
  75. //! Removes all registered consumers, including the default stdout.
  76. RTPS_DllAPI static void ClearConsumers();
  77. //! Enables the reporting of filenames in log entries. Disabled by default.
  78. RTPS_DllAPI static void ReportFilenames(
  79. bool);
  80. //! Enables the reporting of function names in log entries. Enabled by default when supported.
  81. RTPS_DllAPI static void ReportFunctions(
  82. bool);
  83. //! Sets the verbosity level, allowing for messages equal or under that priority to be logged.
  84. RTPS_DllAPI static void SetVerbosity(
  85. Log::Kind);
  86. //! Returns the current verbosity level.
  87. RTPS_DllAPI static Log::Kind GetVerbosity();
  88. //! Sets a filter that will pattern-match against log categories, dropping any unmatched categories.
  89. RTPS_DllAPI static void SetCategoryFilter(
  90. const std::regex&);
  91. //! Sets a filter that will pattern-match against filenames, dropping any unmatched categories.
  92. RTPS_DllAPI static void SetFilenameFilter(
  93. const std::regex&);
  94. //! Sets a filter that will pattern-match against the provided error string, dropping any unmatched categories.
  95. RTPS_DllAPI static void SetErrorStringFilter(
  96. const std::regex&);
  97. //! Returns the logging engine to configuration defaults.
  98. RTPS_DllAPI static void Reset();
  99. //! Waits until no more log info is availabel
  100. RTPS_DllAPI static void Flush();
  101. //! Stops the logging thread. It will re-launch on the next call to a successful log macro.
  102. RTPS_DllAPI static void KillThread();
  103. // Note: In VS2013, if you're linking this class statically, you will have to call KillThread before leaving
  104. // main, due to an unsolved MSVC bug.
  105. struct Context
  106. {
  107. const char* filename;
  108. int line;
  109. const char* function;
  110. const char* category;
  111. };
  112. struct Entry
  113. {
  114. std::string message;
  115. Log::Context context;
  116. Log::Kind kind;
  117. std::string timestamp;
  118. };
  119. /**
  120. * Not recommended to call this method directly! Use the following macros:
  121. * * logInfo(cat, msg);
  122. * * logWarning(cat, msg);
  123. * * logError(cat, msg);
  124. */
  125. RTPS_DllAPI static void QueueLog(
  126. const std::string& message,
  127. const Log::Context&,
  128. Log::Kind);
  129. private:
  130. struct Resources
  131. {
  132. fastrtps::DBQueue<Entry> logs;
  133. std::vector<std::unique_ptr<LogConsumer> > consumers;
  134. std::unique_ptr<std::thread> logging_thread;
  135. // Condition variable segment.
  136. std::condition_variable cv;
  137. std::mutex cv_mutex;
  138. bool logging;
  139. bool work;
  140. int current_loop;
  141. // Context configuration.
  142. std::mutex config_mutex;
  143. bool filenames;
  144. bool functions;
  145. std::unique_ptr<std::regex> category_filter;
  146. std::unique_ptr<std::regex> filename_filter;
  147. std::unique_ptr<std::regex> error_string_filter;
  148. std::atomic<Log::Kind> verbosity;
  149. Resources();
  150. ~Resources();
  151. };
  152. static struct Resources resources_;
  153. // Applies transformations to the entries compliant with the options selected (such as
  154. // erasure of certain context information, or filtering by category. Returns false
  155. // if the log entry is blacklisted.
  156. static bool preprocess(
  157. Entry&);
  158. static void run();
  159. static void get_timestamp(
  160. std::string&);
  161. };
  162. /**
  163. * Consumes a log entry to output it somewhere.
  164. */
  165. class LogConsumer
  166. {
  167. public:
  168. virtual ~LogConsumer()
  169. {
  170. }
  171. virtual void Consume(
  172. const Log::Entry&) = 0;
  173. protected:
  174. void print_timestamp(
  175. std::ostream& stream,
  176. const Log::Entry&,
  177. bool color) const;
  178. void print_header(
  179. std::ostream& stream,
  180. const Log::Entry&,
  181. bool color) const;
  182. void print_context(
  183. std::ostream& stream,
  184. const Log::Entry&,
  185. bool color) const;
  186. void print_message(
  187. std::ostream& stream,
  188. const Log::Entry&,
  189. bool color) const;
  190. void print_new_line(
  191. std::ostream& stream,
  192. bool color) const;
  193. };
  194. #if defined(WIN32)
  195. #define __func__ __FUNCTION__
  196. #endif
  197. #ifndef LOG_NO_ERROR
  198. #define logError_(cat, msg) \
  199. { \
  200. using namespace eprosima::fastdds::dds; \
  201. std::stringstream ss; \
  202. ss << msg; \
  203. Log::QueueLog(ss.str(), Log::Context{__FILE__, __LINE__, __func__, #cat}, Log::Kind::Error); \
  204. }
  205. #elif (defined(__INTERNALDEBUG) || defined(_INTERNALDEBUG))
  206. #define logError_(cat, msg) \
  207. { \
  208. auto tmp_lambda = [&]() \
  209. { \
  210. std::stringstream ss; \
  211. ss << msg; \
  212. }; \
  213. (void)tmp_lambda; \
  214. }
  215. #else
  216. #define logError_(cat, msg)
  217. #endif
  218. #ifndef LOG_NO_WARNING
  219. #define logWarning_(cat, msg) \
  220. { \
  221. using namespace eprosima::fastdds::dds; \
  222. if (Log::GetVerbosity() >= Log::Kind::Warning) \
  223. { \
  224. std::stringstream ss; \
  225. ss << msg; \
  226. Log::QueueLog(ss.str(), Log::Context{__FILE__, __LINE__, __func__, #cat}, Log::Kind::Warning); \
  227. } \
  228. }
  229. #elif (defined(__INTERNALDEBUG) || defined(_INTERNALDEBUG))
  230. #define logWarning_(cat, msg) \
  231. { \
  232. auto tmp_lambda = [&]() \
  233. { \
  234. std::stringstream ss; \
  235. ss << msg; \
  236. }; \
  237. (void)tmp_lambda; \
  238. }
  239. #else
  240. #define logWarning_(cat, msg)
  241. #endif
  242. #if (defined(__INTERNALDEBUG) || defined(_INTERNALDEBUG)) && (defined(_DEBUG) || defined(__DEBUG)) && \
  243. (!defined(LOG_NO_INFO))
  244. #define logInfo_(cat, msg) \
  245. { \
  246. using namespace eprosima::fastdds::dds; \
  247. if (Log::GetVerbosity() >= Log::Kind::Info) \
  248. { \
  249. std::stringstream ss; \
  250. ss << msg; \
  251. Log::QueueLog(ss.str(), Log::Context{__FILE__, __LINE__, __func__, #cat}, Log::Kind::Info); \
  252. } \
  253. }
  254. #elif (defined(__INTERNALDEBUG) || defined(_INTERNALDEBUG))
  255. #define logInfo_(cat, msg) \
  256. { \
  257. auto tmp_lambda = [&]() \
  258. { \
  259. std::stringstream ss; \
  260. ss << msg; \
  261. }; \
  262. (void)tmp_lambda; \
  263. }
  264. #else
  265. #define logInfo_(cat, msg)
  266. #endif
  267. } // namespace dds
  268. } // namespace fastdds
  269. } // namespace eprosima
  270. #endif