/src/Fast-DDS/include/fastdds/dds/log/Log.hpp
Line | Count | Source (jump to first uncovered line) |
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_DDS_LOG__LOG_HPP |
16 | | #define FASTDDS_DDS_LOG__LOG_HPP |
17 | | |
18 | | #include <regex> |
19 | | #include <sstream> |
20 | | |
21 | | #include <fastdds/rtps/attributes/ThreadSettings.hpp> |
22 | | #include <fastdds/fastdds_dll.hpp> |
23 | | |
24 | | /** |
25 | | * eProsima log layer. Logging categories and verbosity can be specified dynamically at runtime. |
26 | | * However, even on a category not covered by the current verbosity level, |
27 | | * there is some overhead on calling a log macro. For maximum performance, you can |
28 | | * opt out of logging any particular level by defining the following symbols: |
29 | | * |
30 | | * * define LOG_NO_ERROR |
31 | | * * define LOG_NO_WARNING |
32 | | * * define LOG_NO_INFO |
33 | | * |
34 | | * Additionally. the lowest level (Info) is disabled by default on release branches. |
35 | | */ |
36 | | |
37 | | // Logging API: |
38 | | |
39 | | // EPROSIMA LOG MACROS |
40 | | //! Logs an info message. Disable it through Log::SetVerbosity, define LOG_NO_INFO, or being in a release branch |
41 | | #define EPROSIMA_LOG_INFO(cat, msg) EPROSIMA_LOG_INFO_IMPL_(cat, msg) |
42 | | //! Logs a warning. Disable reporting through Log::SetVerbosity or define LOG_NO_WARNING |
43 | 4.21k | #define EPROSIMA_LOG_WARNING(cat, msg) EPROSIMA_LOG_WARNING_IMPL_(cat, msg) |
44 | | //! Logs an error. Disable reporting through define LOG_NO_ERROR |
45 | 1.32M | #define EPROSIMA_LOG_ERROR(cat, msg) EPROSIMA_LOG_ERROR_IMPL_(cat, msg) |
46 | | |
47 | | #if ENABLE_OLD_LOG_MACROS_ |
48 | | // Compile old eProsima macros for compatibility shake. |
49 | | // However, these macros will be deprecated in future releases, so please do not use them. |
50 | | |
51 | | //! Logs an info message. Disable it through Log::SetVerbosity, define LOG_NO_INFO, or being in a release branch |
52 | | #define logInfo(cat, msg) logInfo_(cat, msg) |
53 | | //! Logs a warning. Disable reporting through Log::SetVerbosity or define LOG_NO_WARNING |
54 | 0 | #define logWarning(cat, msg) logWarning_(cat, msg) |
55 | | //! Logs an error. Disable reporting through define LOG_NO_ERROR |
56 | | #define logError(cat, msg) logError_(cat, msg) |
57 | | |
58 | | //! Old internal macros. Just kept them in case some crazy bastard thoughtlessly used them |
59 | | #define logInfo_(cat, msg) EPROSIMA_LOG_INFO_IMPL_(cat, msg); |
60 | 0 | #define logWarning_(cat, msg) EPROSIMA_LOG_WARNING_IMPL_(cat, msg); |
61 | | #define logError_(cat, msg) EPROSIMA_LOG_ERROR_IMPL_(cat, msg); |
62 | | |
63 | | #endif // ENABLE_OLD_LOG_MACROS_ |
64 | | |
65 | | namespace eprosima { |
66 | | namespace fastdds { |
67 | | namespace dds { |
68 | | |
69 | | class LogConsumer; |
70 | | |
71 | | /** |
72 | | * Logging utilities. |
73 | | * Logging is accessed through the three macros above, and configuration on the log output |
74 | | * can be achieved through static methods on the class. Logging at various levels can be |
75 | | * disabled dynamically (through the Verbosity level) or statically (through the LOG_NO_[VERB] |
76 | | * macros) for maximum performance. |
77 | | * @ingroup COMMON_MODULE |
78 | | */ |
79 | | class Log |
80 | | { |
81 | | public: |
82 | | |
83 | | /** |
84 | | * Types of log entry. |
85 | | * * Error: Maximum priority. Can only be disabled statically through LOG_NO_ERROR. |
86 | | * * Warning: Medium priority. Can be disabled statically and dynamically. |
87 | | * * Info: Low priority. Useful for debugging. Disabled by default on release branches. |
88 | | */ |
89 | | enum Kind |
90 | | { |
91 | | Error, |
92 | | Warning, |
93 | | Info, |
94 | | }; |
95 | | |
96 | | /** |
97 | | * Registers an user defined consumer to route log output. |
98 | | * There is a default stdout consumer active as default. |
99 | | * @param consumer r-value to a consumer unique_ptr. It will be invalidated after the call. |
100 | | */ |
101 | | FASTDDS_EXPORTED_API static void RegisterConsumer( |
102 | | std::unique_ptr<LogConsumer>&& consumer); |
103 | | |
104 | | //! Removes all registered consumers, including the default stdout. |
105 | | FASTDDS_EXPORTED_API static void ClearConsumers(); |
106 | | |
107 | | //! Enables the reporting of filenames in log entries. Disabled by default. |
108 | | FASTDDS_EXPORTED_API static void ReportFilenames( |
109 | | bool); |
110 | | |
111 | | //! Enables the reporting of function names in log entries. Enabled by default when supported. |
112 | | FASTDDS_EXPORTED_API static void ReportFunctions( |
113 | | bool); |
114 | | |
115 | | //! Sets the verbosity level, allowing for messages equal or under that priority to be logged. |
116 | | FASTDDS_EXPORTED_API static void SetVerbosity( |
117 | | Log::Kind); |
118 | | |
119 | | //! Returns the current verbosity level. |
120 | | FASTDDS_EXPORTED_API static Log::Kind GetVerbosity(); |
121 | | |
122 | | //! Sets a filter that will pattern-match against log categories, dropping any unmatched categories. |
123 | | FASTDDS_EXPORTED_API static void SetCategoryFilter( |
124 | | const std::regex&); |
125 | | |
126 | | //! Unset the category filter. |
127 | | FASTDDS_EXPORTED_API static void UnsetCategoryFilter(); |
128 | | |
129 | | //! Returns whether a category filter was set or not. |
130 | | FASTDDS_EXPORTED_API static bool HasCategoryFilter(); |
131 | | |
132 | | //! Returns a copy of the current category filter or an empty object otherwise |
133 | | FASTDDS_EXPORTED_API static std::regex GetCategoryFilter(); |
134 | | |
135 | | //! Sets a filter that will pattern-match against filenames, dropping any unmatched categories. |
136 | | FASTDDS_EXPORTED_API static void SetFilenameFilter( |
137 | | const std::regex&); |
138 | | |
139 | | //! Returns a copy of the current filename filter or an empty object otherwise |
140 | | FASTDDS_EXPORTED_API static std::regex GetFilenameFilter(); |
141 | | |
142 | | //! Sets a filter that will pattern-match against the provided error string, dropping any unmatched categories. |
143 | | FASTDDS_EXPORTED_API static void SetErrorStringFilter( |
144 | | const std::regex&); |
145 | | |
146 | | //! Sets thread configuration for the logging thread. |
147 | | FASTDDS_EXPORTED_API static void SetThreadConfig( |
148 | | const rtps::ThreadSettings&); |
149 | | |
150 | | //! Returns a copy of the current error string filter or an empty object otherwise |
151 | | FASTDDS_EXPORTED_API static std::regex GetErrorStringFilter(); |
152 | | |
153 | | //! Returns the logging engine to configuration defaults. |
154 | | FASTDDS_EXPORTED_API static void Reset(); |
155 | | |
156 | | //! Waits until all info logged up to the call time is consumed |
157 | | FASTDDS_EXPORTED_API static void Flush(); |
158 | | |
159 | | //! Stops the logging thread. It will re-launch on the next call to a successful log macro. |
160 | | FASTDDS_EXPORTED_API static void KillThread(); |
161 | | |
162 | | // Note: In VS2013, if you're linking this class statically, you will have to call KillThread before leaving |
163 | | // main, due to an unsolved MSVC bug. |
164 | | |
165 | | struct Context |
166 | | { |
167 | | const char* filename; |
168 | | int line; |
169 | | const char* function; |
170 | | const char* category; |
171 | | }; |
172 | | |
173 | | struct Entry |
174 | | { |
175 | | std::string message; |
176 | | Log::Context context; |
177 | | Log::Kind kind; |
178 | | std::string timestamp; |
179 | | }; |
180 | | |
181 | | /** |
182 | | * Not recommended to call this method directly! Use the following macros: |
183 | | * * EPROSIMA_LOG_INFO(cat, msg); |
184 | | * * EPROSIMA_LOG_WARNING(cat, msg); |
185 | | * * EPROSIMA_LOG_ERROR(cat, msg); |
186 | | * |
187 | | * This is a very high sensible point of the code and it should be refactored to be as efficient as possible. |
188 | | */ |
189 | | FASTDDS_EXPORTED_API static void QueueLog( |
190 | | const std::string& message, |
191 | | const Log::Context&, |
192 | | Log::Kind); |
193 | | }; |
194 | | |
195 | | //! Streams Log::Kind serialization |
196 | | inline std::ostream& operator <<( |
197 | | std::ostream& output, |
198 | | const Log::Kind& kind) |
199 | 1.32M | { |
200 | 1.32M | switch (kind){ |
201 | 0 | case Log::Kind::Info: |
202 | 0 | output << "Info"; |
203 | 0 | break; |
204 | | |
205 | 0 | case Log::Kind::Warning: |
206 | 0 | output << "Warning"; |
207 | 0 | break; |
208 | | |
209 | 1.32M | case Log::Kind::Error: |
210 | 1.32M | output << "Error"; |
211 | 1.32M | break; |
212 | | |
213 | 0 | default: |
214 | 0 | output << "Invalid Verbosity Kind."; |
215 | 0 | break; |
216 | 1.32M | } |
217 | | |
218 | 1.32M | return output; |
219 | 1.32M | } |
220 | | |
221 | | /** |
222 | | * Consumes a log entry to output it somewhere. |
223 | | */ |
224 | | class LogConsumer |
225 | | { |
226 | | public: |
227 | | |
228 | 2 | virtual ~LogConsumer() = default; |
229 | | |
230 | | virtual void Consume( |
231 | | const Log::Entry&) = 0; |
232 | | |
233 | | protected: |
234 | | |
235 | | FASTDDS_EXPORTED_API void print_timestamp( |
236 | | std::ostream& stream, |
237 | | const Log::Entry&, |
238 | | bool color) const; |
239 | | |
240 | | FASTDDS_EXPORTED_API void print_header( |
241 | | std::ostream& stream, |
242 | | const Log::Entry&, |
243 | | bool color) const; |
244 | | |
245 | | FASTDDS_EXPORTED_API void print_context( |
246 | | std::ostream& stream, |
247 | | const Log::Entry&, |
248 | | bool color) const; |
249 | | |
250 | | FASTDDS_EXPORTED_API void print_message( |
251 | | std::ostream& stream, |
252 | | const Log::Entry&, |
253 | | bool color) const; |
254 | | |
255 | | FASTDDS_EXPORTED_API void print_new_line( |
256 | | std::ostream& stream, |
257 | | bool color) const; |
258 | | }; |
259 | | |
260 | | #if defined(WIN32) |
261 | | #define __func__ __FUNCTION__ |
262 | | #endif // if defined(WIN32) |
263 | | |
264 | | /******************** |
265 | | * Implementation of the log macros depending on the defined macros: |
266 | | * HAVE_LOG_NO_<level> disable completly a verbosity level |
267 | | * _INTERNALDEBUG || __INTERNALDEBUG force to compile the log macro call even when it would not be added to queue |
268 | | * EPROSIMA_LOG_INFO_IMPL_ would only be compiled if HAVE_LOG_NO_INFO is OFF and |
269 | | * - FASTDDS_ENFORCE_LOG_INFO or (DEBUG and INTERNALDEBUG) are defined |
270 | | * |
271 | | * There are 3 implementations for each level: |
272 | | * 1. Compile and add log to queue |
273 | | * 2. Compile but do not add it to queue (with INTERNALDEBUG) |
274 | | * 3. Do not compile |
275 | | * |
276 | | * Every macro (with implementation) occurs inside a code block so after call every internal variable is destroyed. |
277 | | * Every macro declared has a do while(0). |
278 | | * This will not generate an assembler instruction and forces the user of the macro to use ";" after calling it. |
279 | | * https://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html |
280 | | * NOTE: some compilation cases do not use do while loop and so they do not force ";". |
281 | | * It is a risk that a user takes in exchange of a perfect way of non generating code in such cases. |
282 | | ********************/ |
283 | | |
284 | | /********* |
285 | | * ERROR * |
286 | | *********/ |
287 | | // Name of variables inside macros must be unique, or it could produce an error with external variables |
288 | | #if !HAVE_LOG_NO_ERROR |
289 | | |
290 | | #define EPROSIMA_LOG_ERROR_IMPL_(cat, msg) \ |
291 | 1.32M | do { \ |
292 | 1.32M | std::stringstream fastdds_log_ss_tmp__; \ |
293 | 1.32M | fastdds_log_ss_tmp__ << msg; \ |
294 | 1.32M | eprosima::fastdds::dds::Log::QueueLog( \ |
295 | 1.32M | fastdds_log_ss_tmp__.str(), eprosima::fastdds::dds::Log::Context{__FILE__, __LINE__, __func__, #cat}, \ |
296 | 1.32M | eprosima::fastdds::dds::Log::Kind::Error); \ |
297 | 1.32M | } while (0) |
298 | | |
299 | | #elif (__INTERNALDEBUG || _INTERNALDEBUG) |
300 | | |
301 | | #define EPROSIMA_LOG_ERROR_IMPL_(cat, msg) \ |
302 | | do { \ |
303 | | auto fastdds_log_lambda_tmp__ = [&]() \ |
304 | | { \ |
305 | | std::stringstream fastdds_log_ss_tmp__; \ |
306 | | fastdds_log_ss_tmp__ << msg; \ |
307 | | }; \ |
308 | | (void)fastdds_log_lambda_tmp__; \ |
309 | | } while (0) |
310 | | #else |
311 | | |
312 | | #define EPROSIMA_LOG_ERROR_IMPL_(cat, msg) |
313 | | |
314 | | #endif // ifndef LOG_NO_ERROR |
315 | | |
316 | | /*********** |
317 | | * WARNING * |
318 | | ***********/ |
319 | | #if !HAVE_LOG_NO_WARNING |
320 | | |
321 | | #define EPROSIMA_LOG_WARNING_IMPL_(cat, msg) \ |
322 | 4.21k | do { \ |
323 | 4.21k | if (eprosima::fastdds::dds::Log::GetVerbosity() >= eprosima::fastdds::dds::Log::Kind::Warning) \ |
324 | 4.21k | { \ |
325 | 0 | std::stringstream fastdds_log_ss_tmp__; \ |
326 | 0 | fastdds_log_ss_tmp__ << msg; \ |
327 | 0 | eprosima::fastdds::dds::Log::QueueLog( \ |
328 | 0 | fastdds_log_ss_tmp__.str(), eprosima::fastdds::dds::Log::Context{__FILE__, __LINE__, __func__, #cat}, \ |
329 | 0 | eprosima::fastdds::dds::Log::Kind::Warning); \ |
330 | 0 | } \ |
331 | 4.21k | } while (0) |
332 | | |
333 | | #elif (__INTERNALDEBUG || _INTERNALDEBUG) |
334 | | |
335 | | #define EPROSIMA_LOG_WARNING_IMPL_(cat, msg) \ |
336 | | do { \ |
337 | | auto fastdds_log_lambda_tmp__ = [&]() \ |
338 | | { \ |
339 | | std::stringstream fastdds_log_ss_tmp__; \ |
340 | | fastdds_log_ss_tmp__ << msg; \ |
341 | | }; \ |
342 | | (void)fastdds_log_lambda_tmp__; \ |
343 | | } while (0) |
344 | | |
345 | | #else |
346 | | |
347 | | #define EPROSIMA_LOG_WARNING_IMPL_(cat, msg) |
348 | | |
349 | | #endif // ifndef LOG_NO_WARNING |
350 | | |
351 | | /******** |
352 | | * INFO * |
353 | | ********/ |
354 | | // Allow multiconfig platforms like windows to disable info queueing on Release and other non-debug configs |
355 | | #if !HAVE_LOG_NO_INFO && \ |
356 | | (defined(FASTDDS_ENFORCE_LOG_INFO) || \ |
357 | | ((defined(__INTERNALDEBUG) || defined(_INTERNALDEBUG)) && (defined(_DEBUG) || defined(__DEBUG) || \ |
358 | | !defined(NDEBUG)))) |
359 | | |
360 | | #define EPROSIMA_LOG_INFO_IMPL_(cat, msg) \ |
361 | | do { \ |
362 | | if (eprosima::fastdds::dds::Log::GetVerbosity() >= eprosima::fastdds::dds::Log::Kind::Info) \ |
363 | | { \ |
364 | | std::stringstream fastdds_log_ss_tmp__; \ |
365 | | fastdds_log_ss_tmp__ << msg; \ |
366 | | eprosima::fastdds::dds::Log::QueueLog( \ |
367 | | fastdds_log_ss_tmp__.str(), eprosima::fastdds::dds::Log::Context{__FILE__, __LINE__, __func__, #cat}, \ |
368 | | eprosima::fastdds::dds::Log::Kind::Info); \ |
369 | | } \ |
370 | | } while (0) |
371 | | |
372 | | #elif (__INTERNALDEBUG || _INTERNALDEBUG) |
373 | | |
374 | | #define EPROSIMA_LOG_INFO_IMPL_(cat, msg) \ |
375 | | do { \ |
376 | | auto fastdds_log_lambda_tmp__ = [&]() \ |
377 | | { \ |
378 | | std::stringstream fastdds_log_ss_tmp__; \ |
379 | | fastdds_log_ss_tmp__ << msg; \ |
380 | | }; \ |
381 | | (void)fastdds_log_lambda_tmp__; \ |
382 | | } while (0) |
383 | | |
384 | | #else |
385 | | |
386 | | #define EPROSIMA_LOG_INFO_IMPL_(cat, msg) |
387 | | |
388 | | #endif // ifndef LOG_NO_INFO |
389 | | |
390 | | |
391 | | } // namespace dds |
392 | | } // namespace fastdds |
393 | | } // namespace eprosima |
394 | | |
395 | | #endif // FASTDDS_DDS_LOG__LOG_HPP |